solve optimizer
This commit is contained in:
parent
a59b3a4775
commit
ca0df838a2
17 changed files with 491 additions and 236 deletions
|
@ -1,49 +0,0 @@
|
|||
import FreeCAD
|
||||
import FreeCADGui
|
||||
from PySide import QtGui, QtCore
|
||||
|
||||
class DatumTool:
|
||||
"""
|
||||
A tool for creating datums in existing models
|
||||
"""
|
||||
def __init__(self):
|
||||
self.active = False
|
||||
|
||||
def activate(self):
|
||||
self.active = True
|
||||
FreeCAD.Console.PrintMessage("Datum tool activatedn")
|
||||
|
||||
def deactivate(self):
|
||||
self.active = False
|
||||
FreeCAD.Console.PrintMessage("Datum tool deactivatedn")
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if self.active:
|
||||
# Create a datum at the position of the mouse click
|
||||
pos = FreeCADGui.ActiveDocument.ActiveView.getCursorPos()
|
||||
point = FreeCADGui.ActiveDocument.ActiveView.getPoint(pos)
|
||||
datum = FreeCAD.ActiveDocument.addObject("Part::Datum", "Datum")
|
||||
datum.Placement.Base = point
|
||||
datum.ViewObject.ShapeColor = (0.0, 1.0, 0.0) # Set the color of the datum to green
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
class DatumCommand:
|
||||
"""
|
||||
A command for activating and deactivating the datum tool
|
||||
"""
|
||||
def __init__(self):
|
||||
self.tool = DatumTool()
|
||||
|
||||
def Activated(self):
|
||||
self.tool.activate()
|
||||
FreeCADGui.ActiveDocument.ActiveView.addEventCallback("SoMouseButtonEvent", self.tool.mousePressEvent)
|
||||
|
||||
def Deactivated(self):
|
||||
self.tool.deactivate()
|
||||
FreeCADGui.ActiveDocument.ActiveView.removeEventCallback("SoMouseButtonEvent", self.tool.mousePressEvent)
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': 'path/to/icon.png', 'MenuText': 'Datum Tool', 'ToolTip': 'Creates datum elements in existing models'}
|
||||
|
||||
# Add the command to the Draft Workbench
|
||||
FreeCADGui.addCommand('DatumCommand', DatumCommand())
|
28
freecad_workbench/freecad/robossembler/asm_main.py
Normal file
28
freecad_workbench/freecad/robossembler/asm_main.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
import FreeCAD as App
|
||||
from .geometric_feasibility_predicate.main import main as asm_analysis
|
||||
from get_sequences import process_adjacency_data
|
||||
from valid_sequences import filter_valid_sequences
|
||||
from solve_optimizer import restore_full_sequence # Убедитесь, что эта функция импортирована
|
||||
from constraints_operator import collect_assembly_settings
|
||||
|
||||
def main(flag):
|
||||
# Выполняем анализ сборки и получаем необходимые данные
|
||||
#flag используется для того, чтобы выбирать между обычным и оптимизированным вариантом работы
|
||||
intersection_geometry, sequences, topologyMatrix = asm_analysis()
|
||||
adjacency_matrix = topologyMatrix.matrix
|
||||
assembly_settings = collect_assembly_settings()
|
||||
|
||||
# Упрощаем матрицу смежности
|
||||
if flag:
|
||||
simplified_matrix = simplify_adjacency_matrix(assembly_settings, adjacency_matrix)
|
||||
all_parts, graph, first_detail, leaf_nodes, all_sequences = process_adjacency_data(simplified_matrix)
|
||||
else:
|
||||
all_parts, graph, first_detail, leaf_nodes, all_sequences = process_adjacency_data(adjacency_matrix)
|
||||
|
||||
# Фильтруем допустимые последовательности
|
||||
valid_sequences = filter_valid_sequences(adjacency_matrix, sequences, assembly_settings)
|
||||
full_sequence = restore_full_sequence(assembly_settings, all_sequences)
|
||||
|
||||
return full_sequence
|
||||
|
||||
main()
|
|
@ -35,8 +35,9 @@ def draw_graph(G):
|
|||
plt.show()
|
||||
|
||||
def main():
|
||||
sequence = load_assembly_sequence('assembly_sequence.json')
|
||||
sequence = load_assembly_sequence('/home/markvoltov/GitProjects/framework/test_models/adjacency_matrix.json')
|
||||
assembly_graph = create_assembly_graph(sequence)
|
||||
|
||||
draw_graph(assembly_graph)
|
||||
|
||||
# main()
|
||||
|
|
|
@ -135,6 +135,50 @@ def export_assembly_settings():
|
|||
with open(save_path, "w") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
|
||||
#для работы с данными как с переменной
|
||||
def collect_assembly_settings():
|
||||
doc = App.activeDocument()
|
||||
if not doc:
|
||||
return None
|
||||
|
||||
assembly_settings_folder = None
|
||||
for obj in doc.Objects:
|
||||
if obj.Name == "Assembly_Settings":
|
||||
assembly_settings_folder = obj
|
||||
break
|
||||
|
||||
if not assembly_settings_folder:
|
||||
return None
|
||||
|
||||
assembly_settings = []
|
||||
for obj in assembly_settings_folder.Group:
|
||||
if hasattr(obj, "Type"):
|
||||
obj_dict = {"Name": obj.Name}
|
||||
if obj.Type == "fastener_set":
|
||||
fasteners = [part.Label for part in obj.Fasteners]
|
||||
obj_dict.update({
|
||||
"Type": "fastener_set",
|
||||
"Parent": obj.Parent.Label,
|
||||
"Child": obj.Child.Label,
|
||||
"Fasteners": fasteners
|
||||
})
|
||||
elif obj.Type == "asm_sequence":
|
||||
obj_dict.update({
|
||||
"Type": "asm_sequence",
|
||||
"Parent": obj.Parent.Label,
|
||||
"Child": obj.Child.Label
|
||||
})
|
||||
elif obj.Type == "clearance":
|
||||
partnames = [part.Label for part in obj.PartName]
|
||||
obj_dict.update({
|
||||
"Type": "clearance",
|
||||
"PartName": partnames,
|
||||
"MaxClearance": obj.MaxClearance
|
||||
})
|
||||
assembly_settings.append(obj_dict)
|
||||
|
||||
return assembly_settings
|
||||
|
||||
# create_fastener_set()
|
||||
# create_assembly_sequence()
|
||||
# create_clearance_constraint()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"cadFilePath": "path/to/file",
|
||||
"outPath": "out/path",
|
||||
"cadFilePath": "/home/markvoltov/GitProjects/framework/test_models/test_reductor.FCStd",
|
||||
"outPath": "/home/markvoltov/GitProjects/framework/test_models/",
|
||||
"objectIndentation": 0
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ class AllSequences:
|
|||
for el in v:
|
||||
adj[inc][el - 1] = 1
|
||||
inc += 1
|
||||
return self.find_all_sequences(adj)
|
||||
self.find_all_sequences(adj)
|
||||
|
||||
|
||||
class VectorModel:
|
||||
|
@ -580,8 +580,8 @@ class CadAdjacencyMatrix:
|
|||
collisionResult: int = int(
|
||||
part.Shape.distToShape(nextPart.Shape)[0]
|
||||
)
|
||||
print(collisionResult)
|
||||
print("collisionResult")
|
||||
# print(collisionResult)
|
||||
# print("collisionResult")
|
||||
if collisionResult == 0:
|
||||
matrix[part.Label].append(nextPart.Label)
|
||||
|
||||
|
@ -708,68 +708,82 @@ class ExitFreeCadUseCase:
|
|||
# FreeCadRepository().obj
|
||||
# pass
|
||||
|
||||
#функция, проверяющая, открывается ли программа через консоль или через верстак freecad.
|
||||
def get_paths():
|
||||
if 'FreeCAD' in globals():
|
||||
active_doc = FreeCAD.activeDocument()
|
||||
if active_doc:
|
||||
cadFilePath = active_doc.FileName
|
||||
outPath = os.path.dirname(cadFilePath)
|
||||
else:
|
||||
raise Exception("Нет активного документа в FreeCAD.")
|
||||
else:
|
||||
with open('env.json', 'r', encoding='utf-8') as file:
|
||||
env_data = json.load(file)
|
||||
cadFilePath = env_data.get('cadFilePath')
|
||||
outPath = env_data.get('outPath')
|
||||
if not cadFilePath or not outPath:
|
||||
raise Exception("Не найдены cadFilePath или outPath в env.json.")
|
||||
|
||||
return cadFilePath, outPath
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
env = FS.readJSON("env.json")
|
||||
cadFilePath = str(env["cadFilePath"])
|
||||
outPath = str(env["outPath"])
|
||||
objectIndentation = float(env["objectIndentation"])
|
||||
if 'FreeCAD' in globals():
|
||||
active_doc = FreeCAD.activeDocument()
|
||||
if active_doc:
|
||||
cadFilePath = active_doc.FileName
|
||||
outPath = os.path.dirname(cadFilePath)
|
||||
else:
|
||||
# raise Exception("Нет активного документа в FreeCAD.")
|
||||
# else:
|
||||
env = FS.readJSON("env.json")
|
||||
print(env)
|
||||
cadFilePath = str(env["cadFilePath"])
|
||||
outPath = str(env["outPath"])
|
||||
objectIndentation = float(env["objectIndentation"])
|
||||
|
||||
if cadFilePath == None:
|
||||
return TypeError("CadFile not found env.json")
|
||||
App.open("" + cadFilePath)
|
||||
if cadFilePath == None:
|
||||
return TypeError("CadFile not found env.json")
|
||||
App.open("" + cadFilePath)
|
||||
|
||||
# isAllObjectSolidsCheckUseCase = IsAllObjectSolidsCheckUseCase.call()
|
||||
isAllObjectSolidsCheckUseCase = IsAllObjectSolidsCheckUseCase.call()
|
||||
|
||||
# if isAllObjectSolidsCheckUseCase != None:
|
||||
# FS.writeFile(isAllObjectSolidsCheckUseCase.toString(), outPath, 'error.json')
|
||||
# ExitFreeCadUseCase.call()
|
||||
# return
|
||||
if isAllObjectSolidsCheckUseCase != None:
|
||||
FS.writeFile(isAllObjectSolidsCheckUseCase.toString(), outPath, 'error.json')
|
||||
ExitFreeCadUseCase.call()
|
||||
return
|
||||
|
||||
FreeCAD.open(cadFilePath)
|
||||
|
||||
|
||||
# checkObjectHasTouchesUseCase = CheckObjectHasTouchesUseCase.call(objectIndentation)
|
||||
|
||||
# if checkObjectHasTouchesUseCase != None:
|
||||
# FS.writeFile(checkObjectHasTouchesUseCase.toString(), outPath, 'error.json')
|
||||
# ExitFreeCadUseCase.call()
|
||||
# return
|
||||
|
||||
topologyMatrix = CadAdjacencyMatrix().matrixBySurfaces()
|
||||
import json
|
||||
|
||||
sequences = json.dumps(
|
||||
{"sequences": AllSequences(topologyMatrix.matrix).adj_matrix_names},
|
||||
ensure_ascii=False,
|
||||
indent=4,
|
||||
)
|
||||
sequences = {
|
||||
"sequences": AllSequences(topologyMatrix.matrix).adj_matrix_names
|
||||
}
|
||||
matrix = topologyMatrix.matrix
|
||||
contacts = matrixGetUniqueContact(matrix)
|
||||
intersection_geometry = {"status": True, "recalculations": None}
|
||||
|
||||
for el in contacts:
|
||||
child = App.ActiveDocument.getObjectsByLabel(el.get("child"))[0]
|
||||
parent = App.ActiveDocument.getObjectsByLabel(el.get("parent"))[0]
|
||||
area = IntersectionComputedUseCase.call([child, parent])
|
||||
if area != 0.0:
|
||||
if intersection_geometry.get("recalculations") == None:
|
||||
if intersection_geometry.get("recalculations") is None:
|
||||
intersection_geometry["status"] = False
|
||||
intersection_geometry["recalculations"] = []
|
||||
intersection_geometry["recalculations"].append(
|
||||
{"area": area, "connect": el.get("child") + " " + el.get("parent")}
|
||||
)
|
||||
# print(intersection_geometry, sequences, topologyMatrix.to_dict())
|
||||
return intersection_geometry, sequences, topologyMatrix.to_dict()
|
||||
|
||||
FS.writeFile(
|
||||
json.dumps(intersection_geometry, ensure_ascii=False, indent=4),
|
||||
outPath,
|
||||
"intersection_geometry.json",
|
||||
)
|
||||
FS.writeFile(sequences, outPath, "sequences.json")
|
||||
|
||||
FS.writeFile(
|
||||
json.dumps(topologyMatrix.to_dict(), ensure_ascii=False, indent=4),
|
||||
outPath,
|
||||
"adjacency_matrix.json",
|
||||
)
|
||||
ExitFreeCadUseCase.call()
|
||||
# ExitFreeCadUseCase.call() Сейчас пока не нужна
|
||||
# return intersection_geometry, sequences, topologyMatrix.to_dict()
|
||||
|
||||
|
||||
#main()
|
||||
# main()
|
||||
|
|
|
@ -42,20 +42,36 @@ 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)
|
||||
# data = load_data('/home/markvoltov/GitProjects/framework/test_models/adjacency_matrix.json')
|
||||
# # constraints = load_constraints('constraints.json')
|
||||
# all_parts = data['allParts']
|
||||
# print(all_parts)
|
||||
# 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)
|
||||
# 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')
|
||||
# save_sequences(all_sequences, 'valid_sequences.json')
|
||||
|
||||
print(f"Найдено {len(all_sequences)} допустимых последовательностей сборки.")
|
||||
# print(f"Найдено {len(all_sequences)} допустимых последовательностей сборки.")
|
||||
|
||||
def process_adjacency_data(topology_matrix):
|
||||
all_parts = topology_matrix['allParts']
|
||||
graph = create_graph(topology_matrix)
|
||||
first_detail = topology_matrix['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)
|
||||
|
||||
return all_parts, graph, first_detail, leaf_nodes, all_sequences
|
||||
|
|
|
@ -3,7 +3,7 @@ import networkx as nx
|
|||
import matplotlib.pyplot as plt
|
||||
|
||||
# Загружаем данные из файла
|
||||
with open('adjacency_matrix.json', 'r') as file:
|
||||
with open('/home/markvoltov/GitProjects/framework/freecad_workbench/freecad/robossembler/simplified_adjacency_matrix.json', 'r') as file:
|
||||
data = json.load(file)
|
||||
|
||||
# Создаем пустой граф
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"allParts": [
|
||||
"body_down",
|
||||
"body_up",
|
||||
"sol_gear",
|
||||
"output_shaft",
|
||||
"planet_gear",
|
||||
"planet_gear003",
|
||||
"planet_gear004",
|
||||
"planet_gear005",
|
||||
"planet_gear002",
|
||||
"bolt",
|
||||
"bolt2",
|
||||
"bolt3",
|
||||
"bolt4"
|
||||
],
|
||||
"matrix": {
|
||||
"body_down": [
|
||||
"sol_gear",
|
||||
"planet_gear",
|
||||
"planet_gear003",
|
||||
"planet_gear004",
|
||||
"planet_gear005",
|
||||
"planet_gear002",
|
||||
"body_up"
|
||||
],
|
||||
"body_up": [
|
||||
"body_down",
|
||||
"output_shaft"
|
||||
],
|
||||
"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"
|
||||
]
|
||||
|
||||
}
|
||||
}
|
|
@ -1,112 +1,136 @@
|
|||
import FreeCAD
|
||||
import numpy as np
|
||||
'''
|
||||
Файл, содержащий скрипт для обработки и упрощения матрицы смежности. Запускается через команду в основном меню верстака freecad
|
||||
'''
|
||||
|
||||
|
||||
import json
|
||||
import FreeCAD as App
|
||||
from geometric_feasibility_predicate.main import main as asm_analysis
|
||||
from constraints_operator import collect_assembly_settings
|
||||
|
||||
|
||||
#Запускается после генерации матрицы смежности и разметки изделия
|
||||
# === Для работы с json-файлами. Работает. ===
|
||||
def simplify_adjacency_matrix_json(assembly_file, adjacency_file, output_file):
|
||||
def load_json(file_path):
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
return json.load(file)
|
||||
|
||||
def get_adjacency_matrix_from_file(file_path):
|
||||
with open(file_path, 'r') as f:
|
||||
adjacency_matrix = np.array(json.load(f))
|
||||
#print(adjacency_matrix)
|
||||
return adjacency_matrix
|
||||
def save_json(file_path, data):
|
||||
with open(file_path, 'w', encoding='utf-8') as file:
|
||||
json.dump(data, file, ensure_ascii=False, indent=4)
|
||||
|
||||
assembly_settings = load_json('/assembly_settings.json')
|
||||
adjacency_matrix = load_json('/adjacency_matrix.json')
|
||||
|
||||
fasteners = set()
|
||||
for item in assembly_settings:
|
||||
if item.get("Type") == "fastener_set":
|
||||
fasteners.add(item["Parent"])
|
||||
fasteners.add(item["Child"])
|
||||
|
||||
simplified_matrix = {
|
||||
"allParts": [],
|
||||
"matrix": {}
|
||||
}
|
||||
|
||||
for part in adjacency_matrix["allParts"]:
|
||||
if part not in fasteners:
|
||||
simplified_matrix["allParts"].append(part)
|
||||
neighbors = [
|
||||
neighbor for neighbor in adjacency_matrix["matrix"].get(part, [])
|
||||
if neighbor not in fasteners
|
||||
]
|
||||
if neighbors or part not in fasteners:
|
||||
simplified_matrix["matrix"][part] = neighbors
|
||||
|
||||
save_json(output_file, simplified_matrix)
|
||||
|
||||
|
||||
# simplify_adjacency_matrix('assembly_settings.json', 'adjacency_matrix.json', 'simplified_adjacency_matrix.json')
|
||||
|
||||
|
||||
def restore_full_sequence_json(assembly_file, sequence_file, output_file):
|
||||
def load_json(file_path):
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
return json.load(file)
|
||||
|
||||
def save_json(file_path, data):
|
||||
with open(file_path, 'w', encoding='utf-8') as file:
|
||||
json.dump(data, file, ensure_ascii=False, indent=4)
|
||||
|
||||
assembly_settings = load_json(assembly_file)
|
||||
sequence = load_json(sequence_file)
|
||||
|
||||
full_sequence = []
|
||||
sequence_set = set(sequence)
|
||||
|
||||
for item in sequence:
|
||||
full_sequence.append(item)
|
||||
for setting in assembly_settings:
|
||||
if setting.get("Type") == "fastener_set":
|
||||
parent = setting["Parent"]
|
||||
child = setting["Child"]
|
||||
if parent in sequence_set and child in sequence_set:
|
||||
full_sequence.append(setting["Fasteners"])
|
||||
|
||||
save_json(output_file, full_sequence)
|
||||
|
||||
def get_asm_settings(asm_settings_path):
|
||||
with open(asm_settings_path), 'r') as f:
|
||||
asm_settings = np.array(json.load(f))
|
||||
#print(asm_settings)
|
||||
return asm_settings
|
||||
|
||||
#def get_parts_with_fasteners(asm_settings):
|
||||
'''
|
||||
"Type": "fastener_set",
|
||||
"Parent": obj.Parent.Label,
|
||||
"Child": obj.Child.Label,
|
||||
"Fasteners": fasteners '''
|
||||
#вероятно, тут нужно создавать список объектов
|
||||
|
||||
# fastener_set = []
|
||||
#чтобы это работало, нужно работать с позициями элементов в дереве
|
||||
#возможно, отработает и через лейблы
|
||||
# restore_full_sequence('assembly_settings.json', 'sequence.json', 'full_sequence.json')
|
||||
|
||||
|
||||
#return part_names, fasteners
|
||||
|
||||
def remove_fasteners_from_matrix(adjacency_matrix, part_names, fasteners):
|
||||
fastener_connections = {}
|
||||
indices_to_remove = []
|
||||
# ==== Для работы с внутренними переменными
|
||||
|
||||
for fastener in fasteners:
|
||||
idx = part_names.index(fastener)
|
||||
indices_to_remove.append(idx)
|
||||
def simplify_adjacency_matrix(assembly_settings, adjacency_matrix):
|
||||
fasteners = set()
|
||||
for item in assembly_settings:
|
||||
if item.get("Type") == "fastener_set":
|
||||
fasteners.add(item["Parent"])
|
||||
fasteners.add(item["Child"])
|
||||
|
||||
connected_parts = []
|
||||
for i in range(len(adjacency_matrix)):
|
||||
if adjacency_matrix[i, idx] == 1:
|
||||
connected_parts.append(part_names[i])
|
||||
simplified_matrix = {
|
||||
"allParts": [],
|
||||
"matrix": {}
|
||||
}
|
||||
|
||||
for part in adjacency_matrix["allParts"]:
|
||||
if part not in fasteners:
|
||||
simplified_matrix["allParts"].append(part)
|
||||
neighbors = [
|
||||
neighbor for neighbor in adjacency_matrix["matrix"].get(part, [])
|
||||
if neighbor not in fasteners
|
||||
]
|
||||
if neighbors or part not in fasteners:
|
||||
simplified_matrix["matrix"][part] = neighbors
|
||||
|
||||
return simplified_matrix
|
||||
|
||||
def restore_full_sequence(assembly_settings, sequence):
|
||||
full_sequence = []
|
||||
sequence_set = set(sequence)
|
||||
|
||||
for item in sequence:
|
||||
full_sequence.append(item)
|
||||
for setting in assembly_settings:
|
||||
if setting.get("Type") == "fastener_set":
|
||||
parent = setting["Parent"]
|
||||
child = setting["Child"]
|
||||
if parent in sequence_set and child in sequence_set:
|
||||
full_sequence.append(setting["Fasteners"])
|
||||
|
||||
return full_sequence
|
||||
|
||||
|
||||
def main():
|
||||
App.open("/home/markvoltov/GitProjects/framework/test_models/desk_table.FCStd")
|
||||
|
||||
if App.ActiveDocument:
|
||||
intersection_geometry, sequences, topologyMatrix = asm_analysis()
|
||||
print(sequences)
|
||||
assembly_settings = collect_assembly_settings()
|
||||
simplified_matrix = simplify_adjacency_matrix(assembly_settings, topologyMatrix)
|
||||
|
||||
fastener_connections[fastener] = connected_parts
|
||||
else:
|
||||
print('Ошибка. Нет активного документа!')
|
||||
|
||||
reduced_matrix = np.delete(adjacency_matrix, indices_to_remove, axis=0)
|
||||
reduced_matrix = np.delete(reduced_matrix, indices_to_remove, axis=1)
|
||||
reduced_part_names = [part for part in part_names if part not in fasteners]
|
||||
|
||||
return reduced_matrix, reduced_part_names, fastener_connections
|
||||
|
||||
def save_to_json(data, file_path):
|
||||
with open(file_path, 'w') as f:
|
||||
json.dump(data, f, indent=4)
|
||||
|
||||
|
||||
doc = FreeCAD.ActiveDocument
|
||||
|
||||
|
||||
adjacency_matrix = get_adjacency_matrix_from_file('adjacency_matrix.json')
|
||||
part_names, fasteners = get_parts_with_fasteners(doc)
|
||||
|
||||
# Построение сокращенной матрицы смежности
|
||||
reduced_matrix, reduced_part_names, fastener_connections = remove_fasteners_from_matrix(adjacency_matrix, part_names, fasteners)
|
||||
|
||||
# Сохранение результатов в файлы JSON
|
||||
save_to_json(reduced_matrix.tolist(), 'reduced_adjacency_matrix.json')
|
||||
save_to_json(reduced_part_names, 'reduced_part_names.json')
|
||||
save_to_json(fastener_connections, 'fastener_connections.json')
|
||||
|
||||
|
||||
import json
|
||||
|
||||
|
||||
with open('adjacency_matrix.json') as f:
|
||||
adjacency_matrix = json.load(f)
|
||||
with open('assembly_settings.json') as f:
|
||||
assembly_settings = json.load(f)
|
||||
|
||||
|
||||
fasteners_to_exclude = set()
|
||||
for setting in assembly_settings:
|
||||
if setting.get('Type') == 'fastener_set':
|
||||
fasteners_to_exclude.update(setting.get('Fasteners'))
|
||||
|
||||
|
||||
#for fastener in fasteners_to_exclude:
|
||||
# del adjacency_matrix[fastener]
|
||||
|
||||
#здесь должен запуститься файл генерации последовательности сборки
|
||||
#на вход поступает упрощенная матрица смежности
|
||||
|
||||
|
||||
|
||||
with open('assembly_sequence.json') as f:
|
||||
assembly_sequence = json.load(f)
|
||||
#TODO: сделать в виде функции, вызываемой отдельно
|
||||
#Добавляем крепежи в посл. сборки
|
||||
for setting in assembly_settings:
|
||||
if setting.get('Type') == 'fastener_set':
|
||||
parent = setting.get('Parent')
|
||||
child = setting.get('Child')
|
||||
fasteners = set(setting.get('Fasteners'))
|
||||
for step in assembly_sequence:
|
||||
if step.get('Parent') == parent and step.get('Child') == child:
|
||||
step['Fasteners'] = list(fasteners.intersection(step.get('Fasteners', [])))
|
||||
break
|
||||
main()
|
|
@ -0,0 +1 @@
|
|||
[]
|
|
@ -15,22 +15,29 @@ 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')
|
||||
# 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']
|
||||
# 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)
|
||||
# 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')
|
||||
# save_sequences(valid_sequences, 'valid_sequences.json')
|
||||
|
||||
print(f"Найдено {len(valid_sequences)} допустимых последовательностей сборки.")
|
||||
# print(f"Найдено {len(valid_sequences)} допустимых последовательностей сборки.")
|
||||
|
||||
def filter_valid_sequences(adjacency_matrix, sequences, constraints):
|
||||
all_parts = adjacency_matrix['allParts']
|
||||
first_detail = adjacency_matrix['firstDetail']
|
||||
|
||||
valid_sequences = []
|
||||
for sequence in sequences:
|
||||
if len(set(sequence)) == len(set(all_parts)):
|
||||
valid_sequences.append(sequence)
|
||||
|
||||
return valid_sequences
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"body_down":["body_up","bolt1", "bolt2", "bolt3", "bolt4","sol_gear","planet_gear"],
|
||||
"body_up":["body_down","bolt1", "bolt2", "bolt3", "bolt4","sol_gear"],
|
||||
"body_down":["body_up","bolt1", "bolt2", "bolt3", "bolt4","sol_gear","planet_gear"]
|
||||
}
|
101
test_models/adjacency_matrix.json
Normal file
101
test_models/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
|
||||
}
|
4
test_models/intersection_geometry.json
Normal file
4
test_models/intersection_geometry.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"status": true,
|
||||
"recalculations": null
|
||||
}
|
|
@ -1,10 +1,3 @@
|
|||
{
|
||||
"sequences": [
|
||||
|
||||
"body_down",
|
||||
"sol_gear",
|
||||
"output_shaft",
|
||||
"planet_gear",
|
||||
"planet_gear002"
|
||||
]
|
||||
"sequences": []
|
||||
}
|
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue