ASP refactoring, sequence generation via clusterization

This commit is contained in:
Mark Voltov 2024-02-02 14:22:21 +00:00 committed by Igor Brylyov
parent d2ab856d64
commit fd59ab9e26
45 changed files with 1579 additions and 1267 deletions

View file

@ -0,0 +1,118 @@
from models.all_sequences_model import AllSequencesModel
from repository.file_system_repository import FileSystemRepository
from typing import List, Dict, Any
import json
from models.var import from_str, from_list, from_dict
def reduce(function, iterable, initializer=None):
it = iter(iterable)
if initializer is None:
value = next(it)
else:
value = initializer
for element in it:
value = function(value, element)
return value
def to_ascii_hash(text):
ascii_values = [ord(character) for character in text]
return reduce(lambda x, y: x + y, ascii_values)
class AdjacencyMatrixModel:
matrixError: Dict[str, str] = {}
all_parts: List[str]
first_detail: str
matrix: Dict[str, List[str]]
fileName = "adjacency_matrix.json"
def __init__(
self, all_parts: List[str], first_detail: str, matrix: Dict[str, List[str]]
) -> None:
self.all_parts = all_parts
self.first_detail = first_detail
self.matrix = matrix
self.validateMatrix()
def matrixToFileSystem(self, path: str):
FileSystemRepository.writeFile(
json.dumps(self.to_dict(), ensure_ascii=False, indent=4),
path,
AdjacencyMatrixModel.fileName,
)
pass
def sequencesToFileSystem(self, path: str, restrictions: list[str]):
FileSystemRepository.writeFile(
json.dumps(
{
"sequences": AllSequencesModel(
self.matrix, restrictions
).adj_matrix_names
},
ensure_ascii=False,
indent=4,
),
path,
"sequences.json",
),
pass
def matrixGetUniqueContact(self):
detailsToCheck = []
detailsHashCheck = {}
for k, v in self.matrix.items():
for el in v:
if el != k:
hash = to_ascii_hash(k + el)
if detailsHashCheck.get(hash) == None:
detailsHashCheck[hash] = hash
detailsToCheck.append({"child": el, "parent": k})
return detailsToCheck
def whatPlaceLeadingPartIndex(self):
i = 0
for el in self.matrix:
if el == self.first_detail:
return i
i = +1
def validateMatrix(self):
for el in self.all_parts:
if self.matrix.get(el) == None:
self.matrixError[el] = "Not found adjacency " + el
@staticmethod
def from_dict(obj: Any) -> "AdjacencyMatrixModel":
assert isinstance(obj, dict)
all_pars = from_list(from_str, obj.get("allParts"))
first_detail = from_str(obj.get("firstDetail"))
matrix = from_dict(lambda x: from_list(from_str, x), obj.get("matrix"))
return AdjacencyMatrixModel(all_pars, first_detail, matrix)
def to_dict(self) -> dict:
result: dict = {}
result["allParts"] = from_list(from_str, self.all_parts)
result["firstDetail"] = from_str(self.first_detail)
result["matrix"] = from_dict(lambda x: from_list(from_str, x), self.matrix)
if self.matrixError.values().__len__() == 0:
result["matrixError"] = None
else:
result["matrixError"] = self.matrixError
return result
def getDictMatrix(self) -> dict:
result = {}
for k, v in self.matrix.items():
result[k] = {}
for el in v:
result[k][el] = el
return result

View file

@ -0,0 +1,130 @@
from extensions.list import CoreList
from itertools import repeat
class AllSequencesModel:
"""
A class that processes information from the assembly and creates the objects necessary to create the assembly sequence
"""
all_sequences = None
adj_matrix = None
topologyIds = None
adj_matrix_names = None
def __init__(self, adj_matrix, restrictions: list[str]) -> None:
self.adj_matrix = adj_matrix
self.all_possible_sequences(self.adj_matrix)
self.matrix_by_name()
if restrictions.__len__() != 0:
self.restrictionsValidate(restrictions)
pass
def restrictionsValidate(self, restrictions: CoreList[str]):
"""_summary_
Args:
restrictions (CoreList[str]): _description_
"""
filterMatrix = CoreList()
for el in self.adj_matrix_names:
result = False
for restraint in restrictions:
result = CoreList(el).indexedPriorities(restraint[0], restraint[1])
if result:
filterMatrix.onlyUniqueElementAppend(el)
self.adj_matrix_names = filterMatrix
pass
def matrix_by_name(self):
result = self.all_sequences
inc = 0
for matrix in self.all_sequences:
for index in range(len(matrix)):
result[inc][index] = CoreList(
filter(
lambda el: el.get("number") == matrix[index] + 1,
self.topologyIds,
)
)[0].get("name")
inc += 1
self.adj_matrix_names = result
pass
def find_all_sequences(self, adj_matrix):
"""Find all assembly sequences with dfs
Args:
adj_matrix (dict): Assembly ajacency matrix
"""
sequences = []
num_vertices = len(adj_matrix)
def dfs(vertex, sequence):
sequence.append(vertex)
if len(sequence) == num_vertices:
sequences.append(sequence)
return
for i in range(num_vertices):
if adj_matrix[vertex][i] == 1 and i not in sequence:
dfs(i, sequence.copy())
for i in range(num_vertices):
dfs(i, [])
self.all_sequences = sequences
def findId(self, listMatrix, id):
def filter_odd_num(in_num):
if in_num["name"] == id:
return True
else:
return False
return list(filter(filter_odd_num, listMatrix))[0]["number"]
def iter_paths(self, adj, min_length=6, path=None):
if not path:
for start_node in range(len(adj)):
yield from self.iter_paths(adj, min_length, [start_node])
else:
if len(path) >= min_length:
yield path
if path[-1] in path[:-1]:
return
current_node = path[-1]
for next_node in range(len(adj[current_node])):
if adj[current_node][next_node] == 1:
yield from self.iter_paths(adj, min_length, path + [next_node])
def allUnique(self, x):
seen = set()
return not any(i in seen or seen.add(i) for i in x)
def all_possible_sequences(self, matrix):
topologyIds = []
topologyMatrixNumber = {}
inc = 0
for k, v in matrix.items():
inc += 1
topologyIds.append({"name": k, "number": inc})
inc = 0
for k, v in matrix.items():
inc += 1
topologyMatrixNumber[inc] = list(
map(lambda el: self.findId(topologyIds, el), v)
)
self.topologyIds = topologyIds
adj = []
matrixSize = matrix.keys().__len__()
inc = 0
for k, v in topologyMatrixNumber.items():
adj.append(list(repeat(0, matrixSize)))
for el in v:
adj[inc][el - 1] = 1
inc += 1
return self.find_all_sequences(adj)

View file

@ -0,0 +1,71 @@
from usecases.clear_work_space_document_use_case import (
ClearWorkSpaceDocumentUseCase,
)
from geometric_feasibility_predicate.usecases.get_collision_at_primitive_use_case import (
GetCollisionAtPrimitiveUseCase,
)
from usecases.render_primitive_use_case import RenderPrimitiveUseCase
from usecases.get_part_primitive_coordinates_use_case import (
GetPartPrimitiveCoordinatesUseCase,
)
from usecases.init_parts_parse_use_case import (
InitPartsParseUseCase,
)
from usecases.render_primitives_scenario import RenderPrimitivesScenario
from usecases.get_first_detail_use_case import GetFirstDetailUseCase
from geometric_feasibility_predicate.usecases.get_all_parts_labels_use_case import (
GetAllPartsLabelsUseCase,
)
from models.adjacency_matrix_model import AdjacencyMatrixModel
from repository.freecad_repository import FreeCadRepository
class CadAdjacencyMatrixModel:
"""Class for handling adjacency matrix creation scenario
Returns:
dict: adjacency matrix
"""
def primitiveMatrix(self):
"""get matrix of primitives"""
# Получение матрицы
matrix = RenderPrimitivesScenario(
InitPartsParseUseCase(),
GetPartPrimitiveCoordinatesUseCase(),
RenderPrimitiveUseCase(),
GetCollisionAtPrimitiveUseCase(),
ClearWorkSpaceDocumentUseCase(),
).call()
return AdjacencyMatrixModel(
all_parts=GetAllPartsLabelsUseCase().call(),
first_detail=GetFirstDetailUseCase().call(),
matrix=matrix,
)
# Матрица основанная на соприкосновении обьектов
def matrixBySurfaces(self):
"""Adjacency matrix by touches between parts
Returns:
dict: adjacency matrix
"""
matrix = {}
for part in FreeCadRepository().getAllSolids():
matrix[part.Label] = []
for nextPart in FreeCadRepository().getAllSolids():
if part.Label != nextPart.Label:
# Вычисление соприконсоновения площади деталей
collisionResult: int = int(
part.Shape.distToShape(nextPart.Shape)[0]
)
if collisionResult == 0:
matrix[part.Label].append(nextPart.Label)
return AdjacencyMatrixModel(
all_parts=GetAllPartsLabelsUseCase().call(),
first_detail=GetFirstDetailUseCase().call(),
matrix=matrix,
)

View file

@ -0,0 +1,48 @@
from dataclasses import dataclass
from typing import List, Dict, Any, TypeVar, Callable, Type, cast
from extensions.list import CoreList
from models.var import from_str, from_float
@dataclass
class EnvModel:
cadFilePath: str
outPath: str
solidBodyPadding: float
firstDetail: str
sequencesFixed: list[list[str]]
@staticmethod
def from_dict(obj: Any) -> "EnvModel":
assert isinstance(obj, dict)
cadFilePath = from_str(obj.get("cadFilePath"))
outPath = from_str(obj.get("outPath"))
solidBodyPadding = from_float(obj.get("solidBodyPadding"))
firstDetail = from_str(obj.get("firstDetail"))
sequencesFixed = []
sequencesFixedParse = CoreList(obj.get("sequencesFixed"))
for el in sequencesFixedParse:
sequencesFixed.append(el)
restrictionsOnFasteners = CoreList(obj.get("restrictionsOnFasteners"))
for el in restrictionsOnFasteners:
for part in el["parts"]:
sequencesFixed.append([part, el["fastener"]])
return EnvModel(
cadFilePath,
outPath,
solidBodyPadding,
firstDetail,
sequencesFixed,
)
def to_dict(self) -> dict:
result: dict = {}
result["cadFilePath"] = from_str(self.cadFilePath)
result["outPath"] = from_str(self.outPath)
result["solidBodyPadding"] = from_float(self.solidBodyPadding)
result["firstDetail"] = from_str(self.firstDetail)
result["sequencesFixed"] = self.sequencesFixed
return result

View file

@ -0,0 +1,28 @@
import json
from repository.file_system_repository import FileSystemRepository
from usecases.exit_freecad_use_case import (
ExitFreeCadUseCase,
)
class ErrorStringModel:
def __init__(self, error: str) -> None:
self.error = error
pass
error: str
def toString(self) -> str:
return json.dumps(
{
"error": self.error,
},
ensure_ascii=False,
indent=4,
)
def toFileSystem(self, path: str):
return (
FileSystemRepository.writeFile(self.toString(), path, "error.json"),
ExitFreeCadUseCase.call(),
)

View file

@ -0,0 +1,4 @@
class FreeCadMetaModel(object):
def __init__(self, label, vertex) -> None:
self.label = label
self.vertex = vertex

View file

@ -0,0 +1,41 @@
import uuid
collision_squares_labels = []
class MeshGeometryCoordinateModel(object):
# Получение геометрии мешей
def __init__(
self,
x,
y,
z,
label,
):
self.x = x
self.y = y
self.z = z
self.label = label
self.cadLabel = ""
def initializePrimitivesByCoordinate(self, detailSquares):
import FreeCAD as App
uuidDoc = str(uuid.uuid1())
App.ActiveDocument.addObject("Part::Box", "Box")
App.ActiveDocument.ActiveObject.Label = uuidDoc
App.ActiveDocument.recompute()
part = App.ActiveDocument.getObjectsByLabel(uuidDoc)[0]
collision_squares_labels.append(uuidDoc)
part.Width = 2
part.Height = 2
part.Length = 2
part.Placement = App.Placement(
App.Vector(self.x - 1, self.y - 1, self.z - 1),
App.Rotation(App.Vector(0.00, 0.00, 1.00), 0.00),
)
if detailSquares.get(self.label) is None:
detailSquares[self.label] = []
detailSquares[self.label].append(self)
self.cadLabel = uuidDoc
App.ActiveDocument.recompute()

View file

@ -0,0 +1,51 @@
# Data Conversion Helpers:
from typing import List, Dict, Any, TypeVar, Callable, Type, cast
T = TypeVar("T")
def from_float(x: Any) -> float:
assert isinstance(x, (float, int)) and not isinstance(x, bool)
return float(x)
def to_float(x: Any) -> float:
assert isinstance(x, float)
return x
def from_str(x: Any) -> str:
assert isinstance(x, str)
return x
def from_int(x: Any) -> int:
assert isinstance(x, int) and not isinstance(x, bool)
return x
def to_class(c: Type[T], x: Any) -> dict:
assert isinstance(x, c)
return cast(Any, x).to_dict()
def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
assert isinstance(x, list)
return [f(y) for y in x]
def from_str(x: Any) -> str:
assert isinstance(x, str)
return x
def from_dict(f: Callable[[Any], T], x: Any) -> Dict[str, T]:
assert isinstance(x, dict)
return {k: f(v) for (k, v) in x.items()}
def to_class(c: Type[T], x: Any) -> dict:
assert isinstance(x, c)
return cast(Any, x).to_dict()

View file

@ -0,0 +1,18 @@
class VectorModel:
x: float
y: float
z: float
def __init__(self, cadVector) -> None:
self.x = cadVector[0]
self.y = cadVector[1]
self.z = cadVector[2]
pass
def toFreeCadVector(self):
import FreeCAD as App
return App.Vector(self.x, self.y, self.z)
def toString(self):
return str("x:" + str(self.x) + "y:" + str(self.y) + "z:" + str(self.z))