Compare commits

...
Sign in to create a new pull request.

21 commits

Author SHA1 Message Date
MarkVoltov
862a61b1e7 Генерация последовательностей сборки через кластеризацию и оптимизацию 2024-12-02 00:48:29 +03:00
MarkVoltov
deee7b4329 Path_fix 2024-12-01 22:14:19 +03:00
MarkVoltov
ca0df838a2 solve optimizer 2024-12-01 22:05:03 +03:00
MarkVoltov
a59b3a4775 работа над модулем сборки (в процессе) 2024-11-25 03:16:36 +03:00
ee1afe7869 import pddl fix 2024-11-21 22:59:32 +03:00
0ec56f1eb8 Merge branch 'master' into solve_optimizer 2024-11-21 22:58:12 +03:00
ff087ffbf8 translate fix 2024-11-21 22:57:38 +03:00
ius.mark.alex
70004486c7 Оптимизация расчета последовательности сборки 2024-11-18 02:06:05 +03:00
Mark Voltov
c2e375f854 Add icons and test model 2024-06-19 23:13:31 +03:00
28a8648651 rm json's 2024-06-19 18:59:04 +03:00
4477a15909 Merge branch 'master' into 149-asm-feedback 2024-06-19 17:32:53 +03:00
2b845403cd from main 2024-06-19 17:31:41 +03:00
Mark Voltov
0de605f314 Модуль обратной связи для анализа последовательностей 2024-06-17 02:38:01 +03:00
Mark Voltov
7ffa0acee9 удаление лишних папок 2024-06-03 03:36:54 +03:00
Mark Voltov
ecb43845a6 svg для графа сборки 2024-06-03 03:34:25 +03:00
Mark Voltov
052dd86d94 работающий автодок-генератор 2024-05-26 21:56:16 +03:00
Mark Voltov
8fba62e8a3 обновление файлов asp 2024-05-25 12:12:11 +03:00
Mark Voltov
a4da4aee68 Работающий модуль наложения ограничений 2024-05-17 14:41:01 +03:00
Mark Voltov
db4e0d7ac9 update .gitignore 2024-05-10 11:30:29 +03:00
Mark Voltov
b766e36c31 Добавлен функционал проверки документа 2024-05-10 05:52:32 +03:00
Mark Voltov
3e7bfba178 работа над валидатором геометрии 2024-05-09 15:26:32 +03:00
26 changed files with 653 additions and 173 deletions

View file

@ -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())

View file

@ -0,0 +1,11 @@
Общее руководство работы с планировщиком сборки.
1. Открыть сборку. С помощью команд верстака Robossembler, используя команды "Create Assembly Parameters", "Create fastener set", "Create assembly sequence", произвести разметку элементов сборки. Произвести экспорт настроек с помощью функции
export assembly settings. На выходе получим файл assembly_settings.json
2. Запустить geometric_feasibility_predicate/main.py, указав в env.json значения cadFilePath (путь к сборке) и outPath (путь вывода). Рекомендуется хранить все файлы в одном месте с проектом На выходе получается файл adjacency_matrix.json
3. ( опционально) Запустить файл solve_optimizer , получить упрощенную матрицу смежности в виде reduced_adjacency_matrix.json
4. Произвести расчет последовательности доступным способом, напр. через get_sequences.json или с помощью asp.
5. (Если применено упрощение) Добавить исключенные компоненты с помощью соотв. функции.

View file

@ -1,37 +0,0 @@
# -*- coding: utf8 -*-
#***************************************************************************
#* *
#* Copyright (c) 2020 kbwbe *
#* *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
import FreeCAD
if FreeCAD.GuiUp:
from PySide.QtCore import QT_TRANSLATE_NOOP
from DraftGui import translate
else:
def QT_TRANSLATE_NOOP(context, text):
return text
def translate(context, text):
return text

View file

@ -37,4 +37,4 @@ def draw_graph_with_thumbnails(G, image_folder):
def main():
sequences = load_sequences('valid_sequences.json')
G = create_graph(sequences)
draw_graph_with_thumbnails(G, '/home/markvoltov/GitProjects/framework/test_models/img')
draw_graph_with_thumbnails(G, 'path_to_img')

View 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()

View file

@ -35,8 +35,9 @@ def draw_graph(G):
plt.show()
def main():
sequence = load_assembly_sequence('assembly_sequence.json')
sequence = load_assembly_sequence('path_to_adjacency_matrix.json')
assembly_graph = create_assembly_graph(sequence)
draw_graph(assembly_graph)
# main()

View file

@ -3,7 +3,7 @@ import FreeCADGui as Gui
import Draft
import json
sequence_file = '/home/markvoltov/GitProjects/framework/freecad_workbench/freecad/robossembler/sequences.json'
sequence_file = 'path_to_sequencesjson'
def load_assembly_sequence(filepath):
with open(filepath, 'r') as file:

View file

@ -0,0 +1,82 @@
import networkx as nx
class GraphProcessor:
graph = None
def __init__(self, adjacency_matrix):
self.adjacency_matrix = adjacency_matrix
self.graph = self.load_graph_from_data()
def load_graph_from_data(self):
G = nx.Graph()
for part1, neighbors in self.adjacency_matrix.items():
for neighbor in neighbors:
G.add_edge(part1, neighbor)
return G
class EdgeBetweensClustering:
def __init__(self, graph):
self.graph = graph.copy()
self.clusters = []
def cluster(self):
while self.graph.number_of_edges() > 0:
edge_betweens = nx.edge_betweenness_centrality(self.graph)
max_betweens_edge = max(edge_betweens, key=edge_betweens.get)
self.graph.remove_edge(*max_betweens_edge)
components = list(nx.connected_components(self.graph))
if components not in self.clusters:
self.clusters.append(components)
return []
def get_clusters(self):
return self.clusters
class ClusterisationSequenceUseCase:
def call(self, adjacency_matrix):
graph_processor = GraphProcessor(adjacency_matrix)
G = graph_processor.load_graph_from_data()
ebc = EdgeBetweensClustering(G)
ebc.cluster()
clusters = ebc.get_clusters()
for i in range(len(clusters)):
for j in range(len(clusters[i])):
clusters[i][j] = list(clusters[i][j])
# Создание списка последовательностей сборки
assembly_sequences = []
for cluster in clusters:
sequence = []
for component in cluster:
sequence.extend(component)
assembly_sequences.append(sequence)
return assembly_sequences
# # Вызов функции
# adjacency_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']
# }
# print(adjacency_matrix)
# use_case = ClusterisationSequenceUseCase()
# assembly_sequences = use_case.call(adjacency_matrix)
# print(assembly_sequences)

View file

@ -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()

View file

@ -1,5 +1,5 @@
{
"cadFilePath": "path/to/file",
"outPath": "out/path",
"cadFilePath": "path_to_cad_file",
"outPath": "out_path",
"objectIndentation": 0
}

View file

@ -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()

View file

@ -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('path_to_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

View file

@ -3,7 +3,7 @@ import networkx as nx
import matplotlib.pyplot as plt
# Загружаем данные из файла
with open('adjacency_matrix.json', 'r') as file:
with open('path_tp_simplified_adjacency_matrix.json', 'r') as file:
data = json.load(file)
# Создаем пустой граф

View file

@ -2,7 +2,6 @@ import os
import FreeCADGui as Gui
import FreeCAD as App
from .TranslateUtils import translate
from . import ICONPATH, TRANSLATIONSPATH, Frames
from .version import __version__
@ -15,6 +14,14 @@ __url__ = ["https://robossembler.org"]
__status__ = 'development'
def QT_TRANSLATE_NOOP(ctx, txt):
return txt
def translate(ctx, txt):
return txt
class Robossembler(Gui.Workbench):
"""
class which gets initiated at startup of the gui

View file

@ -105,7 +105,7 @@ def main():
# args.print_helper()
# if (aspDir[aspDir.__len__() - 1] != '/'):
# aspDir += '/'
aspDir = "/home/markvoltov/GitProjects/framework/test_models/"
aspDir = "path_to_models/"
sequences = FS.readJSON(aspDir + 'sequences.json').get('sequences')
assemblyDirNormalize = []

View 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"
]
}
}

View file

@ -0,0 +1,175 @@
'''
Файл, содержащий скрипт для обработки и упрощения матрицы смежности. Запускается через команду в основном меню верстака freecad
'''
import json
import FreeCAD as App
from geometric_feasibility_predicate.main import main as asm_analysis
from constraints_operator import collect_assembly_settings
from clusterisation_sequences import ClusterisationSequenceUseCase
# === Для работы с 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 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)
# restore_full_sequence('assembly_settings.json', 'sequence.json', 'full_sequence.json')
# ==== Для работы с внутренними переменными
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"])
simplified_matrix = {
"allParts": [],
"matrix": {}
}
for part in adjacency_matrix["allParts"]:
# Добавляем все детали, включая крепеж, в simplified_matrix["allParts"]
simplified_matrix["allParts"].append(part)
# Получаем соседей, исключая только крепежные элементы
neighbors = [
neighbor for neighbor in adjacency_matrix["matrix"].get(part, [])
if neighbor not in fasteners
]
# Если у части есть соседи, добавляем их в матрицу
if neighbors:
simplified_matrix["matrix"][part] = neighbors
return simplified_matrix
def restore_full_sequence(assembly_settings, sequences):
full_sequences = []
for sequence in sequences:
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"]
fasteners = setting["Fasteners"]
# Проверяем, если родитель и ребенок в последовательности
if (parent in sequence_set) and (child in sequence_set):
# Находим индексы родителя и ребенка в полной последовательности
parent_index = full_sequence.index(parent)
child_index = full_sequence.index(child)
# Находим максимальный индекс между родителем и ребенком
max_index = max(parent_index, child_index)
# Проверяем, содержатся ли крепежные элементы уже в последовательности
if not any(fastener in full_sequence for fastener in fasteners):
# Добавляем крепежные элементы после элемента child
full_sequence[max_index + 1:max_index + 1] = fasteners
full_sequences.append(full_sequence)
return full_sequences
def main():
App.open('/home/markvoltov/GitProjects/framework/test_models/test_reductor.FCStd')
if App.ActiveDocument:
intersection_geometry, sequences, topologyMatrix = asm_analysis()
assembly_settings = collect_assembly_settings()
print(assembly_settings)
simplified_matrix = simplify_adjacency_matrix(assembly_settings, topologyMatrix)
assembly_sequences = ClusterisationSequenceUseCase().call(topologyMatrix['matrix'])
# print('Последовательности 1', assembly_sequences)
assembly_sequences_simplified= ClusterisationSequenceUseCase().call(simplified_matrix['matrix'])
# print('Последовательности 2',assembly_sequences_simplified)
assembly_sequences_restored = restore_full_sequence(assembly_settings, assembly_sequences_simplified)
print('Последовательности 3',assembly_sequences_restored)
else:
print('Ошибка. Нет активного документа!')
main()

View file

@ -0,0 +1,6 @@
adj_matrix = {
"A": ["B", "C"],
"B": ["C"],
"C": []}
from geometric_feasibility_predicate.main import main as asm_analysis

View file

@ -0,0 +1 @@
[]

View file

@ -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

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
}

Binary file not shown.

0
test_models/env.json Normal file
View file

View file

@ -0,0 +1,4 @@
{
"status": true,
"recalculations": null
}

View file

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

Binary file not shown.