Модуль обратной связи для анализа последовательностей

This commit is contained in:
Mark Voltov 2024-06-17 02:38:01 +03:00
parent 7ffa0acee9
commit 0de605f314
30 changed files with 388 additions and 1611 deletions

View file

@ -8,7 +8,11 @@ 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
from .constraints_operator import create_assembly_parameters, create_fastener_set, create_assembly_sequence, create_clearance_constraint, export_assembly_settings
from .geometric_feasibility_predicate.main import main as structure_analysis
from .asm_graph import main as asm_graph
from .autodock_generator import main as asm_layers
from .assembly_graph_generation import main as structure_graph
if FreeCAD.GuiUp:
import FreeCADGui
@ -331,6 +335,46 @@ spawnClassCommand("Publish_Project",
{"Pixmap": str(os.path.join(ICONPATH, "publish.svg")),
"MenuText": "Publish Project",
"ToolTip": "Save and export project files"})
spawnClassCommand("Create Assembly Parameters",
create_assembly_parameters,
{"Pixmap": str(os.path.join(ICONPATH, ".svg")),
"MenuText": "Create Assembly Parameters",
"ToolTip": "Create Assembly Parameters"})
spawnClassCommand("Create Fastener Set",
create_fastener_set,
{"Pixmap": str(os.path.join(ICONPATH, ".svg")),
"MenuText": "Create Fastener Set",
"ToolTip": "Create Fastener Set"})
spawnClassCommand("Compute Assembly Sequence",
structure_analysis,
{"Pixmap": str(os.path.join(ICONPATH, ".svg")),
"MenuText": "Create Fastener Set",
"ToolTip": "Create Fastener Set"})
spawnClassCommand("Create Assembly Sequence",
create_assembly_sequence,
{"Pixmap": str(os.path.join(ICONPATH, ".svg")),
"MenuText": "Create Assembly Sequence",
"ToolTip": "Create Assembly Sequence"})
spawnClassCommand("Export Assembly Settings",
export_assembly_settings,
{"Pixmap": str(os.path.join(ICONPATH, ".svg")),
"MenuText": "Export Assembly Settings",
"ToolTip": "Export Assembly Settings"})
spawnClassCommand("Create Assembly Layers",
asm_layers,
{"Pixmap": str(os.path.join(ICONPATH, ".svg")),
"MenuText": "Create Assembly Layers",
"ToolTip": "Create Assembly Layers"})
spawnClassCommand("Create Structure Graph",
structure_graph,
{"Pixmap": str(os.path.join(ICONPATH, ".svg")),
"MenuText": "Create Structure Graph",
"ToolTip": "Create Structure Graph"})
spawnClassCommand("Create Assembly Graph",
asm_graph,
{"Pixmap": str(os.path.join(ICONPATH, ".svg")),
"MenuText": "Create Assembly Graph",
"ToolTip": "Create Assembly Graph"})

View file

@ -0,0 +1,101 @@
{
"allParts": [
"body_down",
"sol_gear",
"output_shaft",
"planet_gear",
"planet_gear003",
"planet_gear004",
"planet_gear005",
"planet_gear002",
"body_up",
"bolt",
"bolt2",
"bolt3",
"bolt4"
],
"firstDetail": "body_down",
"matrix": {
"body_down": [
"sol_gear",
"planet_gear",
"planet_gear003",
"planet_gear004",
"planet_gear005",
"planet_gear002",
"body_up",
"bolt",
"bolt2",
"bolt3",
"bolt4"
],
"sol_gear": [
"body_down",
"output_shaft",
"planet_gear",
"planet_gear003",
"planet_gear004",
"planet_gear005",
"planet_gear002"
],
"output_shaft": [
"sol_gear",
"planet_gear",
"planet_gear003",
"planet_gear004",
"planet_gear005",
"planet_gear002",
"body_up"
],
"planet_gear": [
"body_down",
"sol_gear",
"output_shaft"
],
"planet_gear003": [
"body_down",
"sol_gear",
"output_shaft"
],
"planet_gear004": [
"body_down",
"sol_gear",
"output_shaft"
],
"planet_gear005": [
"body_down",
"sol_gear",
"output_shaft"
],
"planet_gear002": [
"body_down",
"sol_gear",
"output_shaft"
],
"body_up": [
"body_down",
"output_shaft",
"bolt",
"bolt2",
"bolt3",
"bolt4"
],
"bolt": [
"body_down",
"body_up"
],
"bolt2": [
"body_down",
"body_up"
],
"bolt3": [
"body_down",
"body_up"
],
"bolt4": [
"body_down",
"body_up"
]
},
"matrixError": null
}

View file

@ -0,0 +1,40 @@
import json
import networkx as nx
import matplotlib.pyplot as plt
import os
def load_sequences(filename):
with open(filename, 'r') as f:
data = json.load(f)
return data['sequences']
def create_graph(sequences):
G = nx.DiGraph()
#for seq in sequences:
for i in range(len(sequences) - 1):
G.add_edge(sequences[i], sequences[i + 1])
return G
def draw_graph_with_thumbnails(G, image_folder):
pos = {}
x = 1
for node in G.nodes():
pos[node] = (1, -x) # Устанавливаем позиции узлов по вертикали
x += 1
plt.figure(figsize=(8, 6))
nx.draw(G, pos, with_labels=True, node_size=100, node_color='skyblue', font_size=10, font_weight='bold')
# for node, (x, y) in pos.items():
# image_path = f"{image_folder}/{node}.svg"
# if os.path.exists(image_path):
# img = plt.imread(image_path)
# plt.imshow(img, aspect='auto', extent=(x - 0.5, x + 0.5, y - 0.5, y + 0.5), zorder=0)
plt.gca().invert_yaxis() # Инвертируем ось y для вертикального отображения
plt.show()
def main():
sequences = load_sequences('valid_sequences.json')
G = create_graph(sequences)
draw_graph_with_thumbnails(G, '/home/markvoltov/GitProjects/framework/test_models/img')

View file

@ -40,5 +40,3 @@ def main():
draw_graph(assembly_graph)
if __name__ == '__main__':
main()

View file

@ -1,4 +1,4 @@
{
"cadFilePath": "/home/markvoltov/GitProjects/framework/test_models/cubes.FCStd",
"outPath": "/home/markvoltov/GitProjects/framework/test_models/"
"cadFilePath": "path/to/file",
"outPath": "out/path"
}

View file

@ -0,0 +1,6 @@
[
[
"Extruder",
"Extruder001"
]
]

View file

@ -86,6 +86,8 @@ def create_assembly_parameters():
assembly_settings_folder.addObject(assembly_parameters)
#экспорт всех заданных настроек в общий файл json
def export_assembly_settings():
doc = App.activeDocument()
@ -133,7 +135,7 @@ def export_assembly_settings():
with open(save_path, "w") as f:
json.dump(data, f, indent=4)
#create_fastener_set()
#create_assembly_sequence()
#create_clearance_constraint()
export_assembly_settings()
# create_fastener_set()
# create_assembly_sequence()
# create_clearance_constraint()
# export_assembly_settings()

View file

@ -1,5 +1,5 @@
{
"cadFilePath": "/home/markvoltov/GitProjects/framework/test_models/cubes.FCStd",
"outPath": "/home/markvoltov/GitProjects/framework/test_models/",
"cadFilePath": "path/to/file",
"outPath": "out/path",
"objectIndentation": 0
}

View file

@ -771,4 +771,4 @@ def main():
ExitFreeCadUseCase.call()
main()
#main()

View file

@ -0,0 +1,61 @@
import json
import networkx as nx
def load_data(file_path):
with open(file_path, 'r') as file:
return json.load(file)
def create_graph(data):
G = nx.Graph()
for part in data['allParts']:
G.add_node(part)
for part, connections in data['matrix'].items():
for connected_part in connections:
G.add_edge(part, connected_part)
return G
def find_leaf_nodes(graph, central_node):
leaf_nodes = []
for node in graph.nodes:
if node != central_node and graph.degree(node) == 1:
leaf_nodes.append(node)
return leaf_nodes
def find_all_paths(graph, start_node, end_node):
try:
return list(nx.all_simple_paths(graph, start_node, end_node))
except nx.NetworkXNoPath:
return []
def load_constraints(file_path):
with open(file_path, 'r') as file:
return json.load(file)
def is_valid_sequence(sequence, constraints):
for constraint in constraints:
if constraint[0] in sequence and constraint[1] in sequence:
if sequence.index(constraint[0]) > sequence.index(constraint[1]):
return False
return True
def save_sequences(sequences, file_path):
with open(file_path, 'w') as file:
json.dump(sequences, file, indent=4)
data = load_data('adjacency_matrix.json')
constraints = load_constraints('constraints.json')
all_parts = data['allParts']
graph = create_graph(data)
first_detail = data['firstDetail']
leaf_nodes = find_leaf_nodes(graph, first_detail)
all_sequences = []
for leaf in leaf_nodes:
paths = find_all_paths(graph, leaf, first_detail)
for path in paths:
if set(path) == set(all_parts) and is_valid_sequence(path, constraints):
all_sequences.append(path)
save_sequences(all_sequences, 'valid_sequences.json')
print(f"Найдено {len(all_sequences)} допустимых последовательностей сборки.")

View file

@ -0,0 +1,26 @@
import json
import networkx as nx
import matplotlib.pyplot as plt
# Загружаем данные из файла
with open('adjacency_matrix.json', 'r') as file:
data = json.load(file)
# Создаем пустой граф
G = nx.Graph()
# Добавляем узлы
for part in data['allParts']:
G.add_node(part)
# Добавляем ребра
for part, connections in data['matrix'].items():
for connected_part in connections:
G.add_edge(part, connected_part)
# Визуализируем граф
plt.figure(figsize=(10, 8))
pos = nx.spring_layout(G)
nx.draw(G, pos, with_labels=True, node_size=100, node_color='lightblue', font_size=10, font_weight='bold', edge_color='gray')
plt.title('Graph of Part Connections')
plt.show()

View file

@ -38,8 +38,7 @@ class Robossembler(Gui.Workbench):
self.framecommands = [
"BoMGeneration",
"FrameCommand",
"FrameCommand",
"SelectedPartFrameCommand",
"AllPartFramesCommand",
"FeatureFrameCommand"
@ -52,8 +51,21 @@ class Robossembler(Gui.Workbench):
"Validate_Project",
"Publish_Project"
]
self.asmcommands = [
"Create Assembly Parameters",
"Create Fastener Set",
"Create Assembly Sequence",
"Export Assembly Settings",
"Compute Assembly Sequence",
"Create Assembly Layers",
"Create Structure Graph",
"Create Assembly Graph"
]
self.appendToolbar(f"{__class__.__name__} Frames", self.framecommands)
self.appendToolbar(f"{__class__.__name__} Tools", self.toolcommands)
self.appendToolbar(f"{__class__.__name__} Assembly Setup", self.asmcommands)
App.Console.PrintMessage(translate("Console",
"Switching to robossembler") + "\n")

View file

@ -1,10 +0,0 @@
{
"sequences": [
"body_down",
"sol_gear",
"output_shaft",
"planet_gear",
"planet_gear002"
]
}

View file

@ -0,0 +1,14 @@
{"sequences":[
"PTFE Tube Nut M6 v1",
"PTFE Tube Nut M6 v002",
"Extruder002",
"Extruder",
"Extruder001",
"91239A140_Button Head Hex Drive Screw",
"Hotend002",
"Hotend001",
"Hotend003",
"Extruder003",
"Extruder004",
"Hotend"
]}

View file

@ -0,0 +1,36 @@
import json
def load_data(file_path):
with open(file_path, 'r') as file:
return json.load(file)
def is_valid_sequence(sequence, constraints):
for constraint in constraints:
if constraint[0] in sequence and constraint[1] in sequence:
if sequence.index(constraint[0]) > sequence.index(constraint[1]):
return False
return True
def save_sequences(sequences, file_path):
with open(file_path, 'w') as file:
json.dump(sequences, file, indent=4)
# Load data from files
adjacency_matrix = load_data('adjacency_matrix.json')
constraints = load_data('constraints.json')
sequences = load_data('sequences.json')
# Get all parts and first detail
all_parts = adjacency_matrix['allParts']
first_detail = adjacency_matrix['firstDetail']
# Filter valid sequences
valid_sequences = []
for sequence in sequences:
if len(set(sequence)) == len(set(all_parts)): #and is_valid_sequence(sequence, constraints):
valid_sequences.append(sequence)
# Save valid sequences to file
save_sequences(valid_sequences, 'valid_sequences.json')
print(f"Найдено {len(valid_sequences)} допустимых последовательностей сборки.")

View file

@ -0,0 +1,34 @@
[
{
"Name": "Fastener_Set",
"Type": "fastener_set",
"Parent": "body_down",
"Child": "body_up",
"Fasteners": [
"bolt4",
"bolt",
"bolt2",
"bolt3"
]
},
{
"Name": "Assembly_Sequence",
"Type": "asm_sequence",
"Parent": "body_down",
"Child": "sol_gear"
},
{
"Name": "Clearance_Constraint",
"Type": "clearance",
"PartName": [
"planet_gear002",
"planet_gear005",
"planet_gear004",
"planet_gear003",
"planet_gear",
"output_shaft",
"sol_gear"
],
"MaxClearance": 1.0
}
]

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 650 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 658 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 728 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 104 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 104 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 104 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 104 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 104 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 414 KiB