Модуль обратной связи для анализа последовательностей
|
@ -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"})
|
||||
|
||||
|
||||
|
||||
|
|
101
freecad_workbench/freecad/robossembler/adjacency_matrix.json
Normal 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
|
||||
}
|
40
freecad_workbench/freecad/robossembler/asm_graph.py
Normal 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')
|
|
@ -40,5 +40,3 @@ def main():
|
|||
|
||||
draw_graph(assembly_graph)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
6
freecad_workbench/freecad/robossembler/constraints.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
[
|
||||
"Extruder",
|
||||
"Extruder001"
|
||||
]
|
||||
]
|
|
@ -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()
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -771,4 +771,4 @@ def main():
|
|||
ExitFreeCadUseCase.call()
|
||||
|
||||
|
||||
main()
|
||||
#main()
|
||||
|
|
61
freecad_workbench/freecad/robossembler/get_sequences.py
Normal 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)} допустимых последовательностей сборки.")
|
|
@ -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()
|
|
@ -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")
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"sequences": [
|
||||
|
||||
"body_down",
|
||||
"sol_gear",
|
||||
"output_shaft",
|
||||
"planet_gear",
|
||||
"planet_gear002"
|
||||
]
|
||||
}
|
14
freecad_workbench/freecad/robossembler/valid_sequences.json
Normal 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"
|
||||
]}
|
36
freecad_workbench/freecad/robossembler/valid_sequences.py
Normal 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)} допустимых последовательностей сборки.")
|
34
test_models/assembly_settings_test_reductor.json
Normal 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
|
||||
}
|
||||
]
|
Before Width: | Height: | Size: 650 KiB |
Before Width: | Height: | Size: 658 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 728 KiB |
Before Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 414 KiB |