diff --git a/geometric_feasibility_predicate/env.json b/geometric_feasibility_predicate/env.json index 2203e0c..29d89bc 100644 --- a/geometric_feasibility_predicate/env.json +++ b/geometric_feasibility_predicate/env.json @@ -1,5 +1,8 @@ { - "cadFilePath": "/Users/idontsudo/Desktop/asp-example/disk_and_axis_n.FCStd", - "outPath": "/Users/idontsudo/Desktop/asp-example/", - "objectIndentation": 0 + "cadFilePath": "/Users/idontsudo/Desktop/reductor/test_reductor.FCStd", + "outPath": "/Users/idontsudo/Desktop/reductor/", + "solidBodyPadding": 1, + "firstDetail": "Куб", + "sequencesFixed": [], + "restrictionsOnFasteners": [] } diff --git a/geometric_feasibility_predicate/main.py b/geometric_feasibility_predicate/main.py index 690bc2a..d46096a 100644 --- a/geometric_feasibility_predicate/main.py +++ b/geometric_feasibility_predicate/main.py @@ -4,16 +4,255 @@ import os import json from typing import List, Dict, Any, TypeVar, Callable, Type, cast from itertools import repeat +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import Any, TypeVar, Type, cast + + +T = TypeVar("T") + + +class BackgroundConsoleColors: + HEADER = "\033[95m" + OKBLUE = "\033[94m" + OKCYAN = "\033[96m" + OKGREEN = "\033[92m" + WARNING = "\033[93m" + FAIL = "\033[91m" + ENDC = "\033[0m" + BOLD = "\033[1m" + UNDERLINE = "\033[4m" + + +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() + + +@dataclass +class Env: + cadFilePath: str + outPath: str + solidBodyPadding: float + firstDetail: str + sequencesFixed: list[list[str]] + + @staticmethod + def from_dict(obj: Any) -> "Env": + 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 Env( + 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 + + +class Either(ABC): + @abstractmethod + def isLeft(self): + pass + + @abstractmethod + def isRight(self): + pass + + @abstractmethod + def getLeft(self): + pass + + @abstractmethod + def getRight(self): + pass + + @abstractmethod + def mapLeft(self, lf): + pass + + @abstractmethod + def mapRight(self, rf): + pass + + @abstractmethod + def either(self, leftF, rightF): + pass + + +class Left(Either): + def __init__(self, lvalue): + self.lvalue = lvalue + + def isLeft(self): + return True + + def isRight(self): + return False + + def getLeft(self): + return self.lvalue + + def getRight(self): + raise Error("Cannot get a right value out of Left.") + + def mapLeft(self, lf): + return Left(lf(self.lvalue)) + + def mapRight(self, rf): + return Left(self.lvalue) + + def either(self, leftF, rightF): + return leftF(self.lvalue) + + +class Right(Either): + def __init__(self, rvalue): + self.rvalue = rvalue + + def isLeft(self): + return False + + def isRight(self): + return True + + def getLeft(self): + raise Error("Cannot get a left value out of Right.") + + def getRight(self): + return self.rvalue + + def mapLeft(self, lf): + return Right(self.rvalue) + + def mapRight(self, rf): + return Right(rf(self.rvalue)) + + def either(self, leftF, rightF): + return rightF(self.rvalue) + + +class CoreDict(dict): + def isEquivalentByKeys(self, checkDict) -> bool: + print(checkDict) + for key in self: + value = checkDict.get(key) + if value is None: + return False + + return True + + def isMatchByKeys(self, checkList): + if len(self) != len(checkList): + return False + + sorted_dict_keys = sorted(self.keys()) + sorted_list_elements = sorted(checkList) + + if sorted_dict_keys != sorted_list_elements: + missing_keys = [ + key for key in sorted_list_elements if key not in sorted_dict_keys + ] + print(f"Отсутствующие ключи в словаре: {missing_keys}") + return False + + return True class CoreList(List): - # the list contains only True def onlyTrue(self) -> bool: - print(self) for el in self: - if el is not True: - return False - return True + if el is True: + return True + return False + + def onlyUniqueElementAppend(self, el): + if el is None: + return + if self.is_element_in_array(el) is False: + self.append(el) + pass + + def is_element_in_array(self, element): + return element in self + + def equal(self, array: list) -> bool: + if len(self) != len(array): + return False + return self.sort() == array.sort() + + def isConstrainsString(self) -> bool: + for el in self: + if isinstance(el, str): + return True + return False + + def indexedPriorities(self, lowerPriority, highPriority) -> bool: + try: + lowerIndex = self.index(lowerPriority) + highPriorityIndex = self.index(highPriority) + return lowerIndex < highPriorityIndex + except: + return False + + def getAllString(self) -> list[str]: + return list(filter(lambda x: isinstance(x, str), self)) + + def onlyUnique(self) -> list: + result = [] + [result.append(x) for x in self if x not in self] + return result + + def spreadArray(self) -> "CoreList": + unpacked_array = CoreList([]) + for el in self: + if isinstance(el, list): + unpacked_array.extend(el) + else: + unpacked_array.append(el) + return unpacked_array def isInListRange(listIn, index): @@ -30,10 +269,24 @@ class AllSequences: topologyIds = None adj_matrix_names = None - def __init__(self, adj_matrix) -> 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]): + 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): @@ -41,7 +294,7 @@ class AllSequences: inc = 0 for matrix in self.all_sequences: for index in range(len(matrix)): - result[inc][index] = list( + result[inc][index] = CoreList( filter( lambda el: el.get("number") == matrix[index] + 1, self.topologyIds, @@ -137,10 +390,29 @@ class VectorModel: def toFreeCadVector(self): 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)) + class FreeCadRepository: _solids = [] + def openDocument(self, path: str): + App.open("" + path) + + def closeIfOpenDocument(self): + # print('Проверка на документ') + try: + if App.ActiveDocument is not None: + # print(App.ActiveDocument.name + "закрыт") + # App.closeDocument(App.ActiveDocument.name) + App.ActiveDocument.clearDocument() + except Exception as e: + print(e) + + def getAllLabelsSolids(self) -> List[str]: + return list(map(lambda el: el.Label, self.getAllSolids())) + def isAllObjectsSolids(self) -> List[str]: result = [] for part in App.ActiveDocument.Objects: @@ -155,79 +427,98 @@ class FreeCadRepository: def objectGetPosition(self, solid) -> VectorModel: return VectorModel(cadVector=solid.Placement.Base) - def isObjectIntersections(self, part) -> bool: + def isObjectIntersections(self, part) -> str: + result = [] for solid in self.getAllSolids(): - if solid.Label != part.Label: + if solid.ID != part.ID: collisionResult: int = int(part.Shape.distToShape(solid.Shape)[0]) if collisionResult == 0: - return True - return False + result.append(solid.Label) + if result.__len__() == 0: + return None + return result - def objectHasTouches(self, part, objectIndentation: float) -> List[str]: - positionVector = self.objectGetPosition(part) - result = CoreList() - result.append(self.isObjectIntersections(part=part)) - - if objectIndentation != 0 and objectIndentation != None: - result.append( - self.axis_movement_and_intersections_observer( - positionVector=positionVector, - alongAxis="x", - objectIndentation=objectIndentation, - part=part, + def objectHasTouches(self, part, solidBodyPadding: float) -> List[str]: + try: + positionVector = self.objectGetPosition(part) + result = CoreList() + result.append(self.isObjectIntersections(part=part)) + if solidBodyPadding != 0 and solidBodyPadding != None: + result.append( + self.axis_movement_and_intersections_observer( + positionVector=positionVector, + alongAxis="x", + solidBodyPadding=solidBodyPadding, + part=part, + ) ) - ) - result.append( - self.axis_movement_and_intersections_observer( - positionVector=positionVector, - alongAxis="y", - objectIndentation=objectIndentation, - part=part, + result.append( + self.axis_movement_and_intersections_observer( + positionVector=positionVector, + alongAxis="y", + solidBodyPadding=solidBodyPadding, + part=part, + ) ) - ) - result.append( - self.axis_movement_and_intersections_observer( - positionVector=positionVector, - alongAxis="z", - objectIndentation=objectIndentation, - part=part, + result.append( + self.axis_movement_and_intersections_observer( + positionVector=positionVector, + alongAxis="z", + solidBodyPadding=solidBodyPadding, + part=part, + ) ) - ) - - return result.onlyTrue() + spreadArr = result.spreadArray() + if spreadArr.isConstrainsString(): + return spreadArr.getAllString() + return None + except Exception as error: + print(error) + return None def axis_movement_and_intersections_observer( self, positionVector: VectorModel, alongAxis: str, - objectIndentation: float, + solidBodyPadding: float, part, ) -> bool: + result = CoreList() # UP positionVector.__setattr__( - alongAxis, positionVector.__getattribute__(alongAxis) + objectIndentation + alongAxis, + positionVector.__getattribute__(alongAxis) + solidBodyPadding, ) self.objectSetPosition(part, positionVector.toFreeCadVector()) - result = self.isObjectIntersections(part=part) - if result: - return True + # result.onlyUniqueElementAppend(self.isObjectIntersections(part=part)) + result.extend(self.isObjectIntersections(part=part)) + # RESET UP CHANGES + positionVector.__setattr__( + alongAxis, + positionVector.__getattribute__(alongAxis) - solidBodyPadding, + ) + self.objectSetPosition(part, positionVector.toFreeCadVector()) + # DOWN positionVector.__setattr__( - alongAxis, positionVector.__getattribute__(alongAxis) - objectIndentation - ) - positionVector.__setattr__( - alongAxis, positionVector.__getattribute__(alongAxis) - objectIndentation - ) - result = self.isObjectIntersections(part=part) - if result: - return True - self.isObjectIntersections(part=part) - # ROLLBACK - positionVector.__setattr__( - alongAxis, positionVector.__getattribute__(alongAxis) + objectIndentation + alongAxis, + positionVector.__getattribute__(alongAxis) - solidBodyPadding, ) self.objectSetPosition(part, positionVector.toFreeCadVector()) - return False + # CHECK DOWN INTERSECTIONS + # result.onlyUniqueElementAppend(self.isObjectIntersections(part=part)) + result.extend(self.isObjectIntersections(part=part)) + + # RESET DOWN CHANGES + positionVector.__setattr__( + alongAxis, + positionVector.__getattribute__(alongAxis) + solidBodyPadding, + ) + self.objectSetPosition(part, positionVector.toFreeCadVector()) + if result.__len__() == 0: + return None + + return result.onlyUnique() def getAllSolids(self): if self._solids.__len__() == 0: @@ -286,6 +577,8 @@ class AdjacencyMatrix: 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: @@ -294,6 +587,38 @@ class AdjacencyMatrix: self.matrix = matrix self.validateMatrix() + def matrixToFileSystem(self, path: str): + FileSystemRepository.writeFile( + json.dumps(self.to_dict(), ensure_ascii=False, indent=4), + path, + AdjacencyMatrix.fileName, + ) + pass + + def sequencesToFileSystem(self, path: str, restrictions: list[str]): + FileSystemRepository.writeFile( + json.dumps( + {"sequences": AllSequences(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: @@ -309,6 +634,7 @@ class AdjacencyMatrix: @staticmethod def from_dict(obj: Any) -> "AdjacencyMatrix": 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")) @@ -393,7 +719,7 @@ class MeshGeometryCoordinateModel(object): App.ActiveDocument.recompute() -class FS: +class FileSystemRepository: def readJSON(path: str): return json.loads((open(path)).read()) @@ -580,8 +906,7 @@ class CadAdjacencyMatrix: collisionResult: int = int( part.Shape.distToShape(nextPart.Shape)[0] ) - print(collisionResult) - print("collisionResult") + if collisionResult == 0: matrix[part.Label].append(nextPart.Label) @@ -608,19 +933,6 @@ def to_ascii_hash(text): return reduce(lambda x, y: x + y, ascii_values) -def matrixGetUniqueContact(matrix): - detailsToCheck = [] - detailsHashCheck = {} - for k, v in 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 - - class IntersectionComputedUseCase: def call(parts): App.activeDocument().addObject("Part::MultiCommon", "Common") @@ -657,32 +969,55 @@ class ErrorStringModel: indent=4, ) + def toFileSystem(self, path: str): + return ( + FileSystemRepository.writeFile(self.toString(), path, "error.json"), + ExitFreeCadUseCase.call(), + ) + class IsAllObjectSolidsCheckUseCase: - def call() -> ErrorStringModel: + def call() -> Either: result = FreeCadRepository().isAllObjectsSolids() if result.__len__() == 0: - return None + return Left(None) - return ErrorStringModel(error="Is not solid objects: " + ",".join(result)) + return Right( + ErrorStringModel(error="Is not solid objects: " + ",".join(result)) + ) class CheckObjectHasTouchesUseCase: - def call(objectIndentation: float) -> ErrorStringModel: - result = [] - for part in FreeCadRepository().getAllSolids(): - if ( - FreeCadRepository().objectHasTouches( - part=part, objectIndentation=objectIndentation + freeCadRepository = FreeCadRepository() + + def call(self, solidBodyPadding: float) -> Either: + try: + errorResult = [] + matrix = {} + for part in self.freeCadRepository.getAllSolids(): + matrix[part.Label] = [] + touches = FreeCadRepository().objectHasTouches( + part=part, solidBodyPadding=solidBodyPadding ) - is False - ): - result.append(part.Label) - if result.__len__() == 0: - return None - return ErrorStringModel( - error="Solids bodies have no recounts: " + ",".join(result) - ) + matrix[part.Label].extend(touches) + if errorResult.__len__() == 0: + return Left( + AdjacencyMatrix( + all_parts=self.freeCadRepository.getAllLabelsSolids(), + first_detail=GetFirstDetailUseCase().call(), + matrix=matrix, + ) + ) + else: + return Right( + ErrorStringModel( + error="Solids bodies have no recounts: " + ",".join(errorResult) + ) + ) + except Exception as error: + print(error) + print("CheckObjectHasTouchesUseCase error") + return Right(ErrorStringModel(error="CheckObjectHasTouchesUseCase error")) class CheckCadIntersectionObjects: @@ -697,6 +1032,7 @@ class ExitFreeCadUseCase: def call(): import FreeCADGui as Gui + App.ActiveDocument.clearDocument() freecadQTWindow = Gui.getMainWindow() freecadQTWindow.close() @@ -709,66 +1045,272 @@ class ExitFreeCadUseCase: # pass +class EnvReaderUseCase: + def call() -> Either: + try: + return Left(Env.from_dict(FileSystemRepository.readJSON("env.json"))) + except: + print("env reader error") + return Right(None) + + +class OpenFreeCadDocumentUseCase: + def call(path: str) -> Either: + try: + FreeCadRepository().closeIfOpenDocument() + FreeCadRepository().openDocument(path) + return Left(None) + except: + print("OpenFreeCadDocumentUseCase error") + return Right(None) + + +class IntersectionGeometryUseCase: + def call(contacts, path): + 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: + intersection_geometry["status"] = False + intersection_geometry["recalculations"] = [] + intersection_geometry["recalculations"].append( + {"area": area, "connect": el.get("child") + " " + el.get("parent")} + ) + FileSystemRepository.writeFile( + json.dumps(intersection_geometry, ensure_ascii=False, indent=4), + path, + "intersection_geometry.json", + ) + + def main(): - env = FS.readJSON("env.json") - cadFilePath = str(env["cadFilePath"]) - outPath = str(env["outPath"]) - objectIndentation = float(env["objectIndentation"]) + try: + EnvReaderUseCase.call().either( + leftF=lambda environment: ( + OpenFreeCadDocumentUseCase.call(environment.cadFilePath).either( + leftF=lambda _: ( + IsAllObjectSolidsCheckUseCase.call().either( + leftF=lambda _: ( + CheckObjectHasTouchesUseCase() + .call(environment.solidBodyPadding) + .either( + leftF=lambda adjaxedMatrix: ( + adjaxedMatrix.sequencesToFileSystem( + environment.outPath, + environment.sequencesFixed, + ), + IntersectionGeometryUseCase.call( + adjaxedMatrix.matrixGetUniqueContact(), + environment.outPath, + ), + adjaxedMatrix.matrixToFileSystem( + environment.outPath, + ), + ExitFreeCadUseCase.call(), + ), + rightF=lambda error: error.toFileSystem( + environment.outPath + ), + ), + ), + rightF=lambda error: error.toFileSystem( + environment.outPath + ), + ), + ), + rightF=lambda error: print(error), + ), + ), + rightF=lambda error: print(error), + ) - if cadFilePath == None: - return TypeError("CadFile not found env.json") - App.open("" + cadFilePath) + except Exception as error: + print(error) + ExitFreeCadUseCase.call() - # isAllObjectSolidsCheckUseCase = IsAllObjectSolidsCheckUseCase.call() - # if isAllObjectSolidsCheckUseCase != None: - # FS.writeFile(isAllObjectSolidsCheckUseCase.toString(), outPath, 'error.json') - # ExitFreeCadUseCase.call() - # return +# main() - # 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, - ) - 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: - intersection_geometry["status"] = False - intersection_geometry["recalculations"] = [] - intersection_geometry["recalculations"].append( - {"area": area, "connect": el.get("child") + " " + el.get("parent")} +class ReadFileSystemAndGetInstanceModelUseCase: + def call(self, model, path): + if hasattr(model, "from_dict") is False: + return Right( + "ReadFileSystemAndGetInstanceModelUseCase error:" + + model + + "is not have method" + + "from_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() + try: + return Left(model.from_dict(FileSystemRepository.readJSON(path))) + except: + error = str(model) + " " + "from dict error " + "path: " + path + print("ReadFileSystemAndGetInstanceModelUseCase error" + error) + return Right(error) + pass -main() +class FreeCadTest: + testName: str + + def testHelper(self, testResult): + if isinstance(testResult, bool) is False: + print( + BackgroundConsoleColors.WARNING, + self.testName + + " expected a value of type Boolean, returned a value of type below ", + ) + print(testResult) + return + if testResult: + print(BackgroundConsoleColors.OKGREEN, self.testName + "is complete!") + else: + print(BackgroundConsoleColors.FAIL, self.testName + " is Error!") + pass + + +class FreeCadASPGenerationTestController(FreeCadTest): + testName: str + + def __init__(self, testName: str) -> None: + self.testName = testName + pass + + def test( + self, + assertFn, + documentPath: str, + modelName: str, + model, + execComposition, + outPath=os.path.dirname(__file__) + "/out/", + ): + try: + OpenFreeCadDocumentUseCase.call(documentPath).either( + leftF=lambda _: ( + execComposition(""), + ReadFileSystemAndGetInstanceModelUseCase() + .call(model=model, path=outPath + modelName) + .either( + leftF=lambda model: ( + self.testHelper( + assertFn(model), + ) + ), + rightF=lambda error: print(error), + ), + ), + rightF=lambda error: print(error), + ) + except Exception as inst: + print("FreeCadASPGenerationTestController error") + print(inst) + pass + + +def test(): + try: + mocksFolder = os.path.dirname(__file__) + "/mocks/" + outFolder = os.path.dirname(__file__) + "/out/" + + # FreeCadASPGenerationTestController("test adjaxed matrix simple cube").test( + # assertFn=lambda model: CoreList(model.all_parts).equal(["Куб", "Куб001"]), + # execComposition=lambda _: ( + # CheckObjectHasTouchesUseCase() + # .call(0) + # .either( + # leftF=lambda matrix: matrix.matrixToFileSystem(outFolder), + # rightF=lambda error: print(error), + # ) + # ), + # documentPath=mocksFolder + "simple_assembly_with_two_cubes.FCStd", + # modelName=AdjacencyMatrix.fileName, + # model=AdjacencyMatrix, + # ) + + FreeCadASPGenerationTestController( + "test adjaxed matrix vs structure of document" + ).test( + assertFn=lambda model: CoreDict(model.matrix).isEquivalentByKeys( + { + "Бутылочный домкрат 4т_Гильза": [ + "Бутылочный домкрат 4т_Тяга", + "Бутылочный домкрат 4т_Тяга001", + "Бутылочный домкрат 4т_Шток насоса", + "Бутылочный домкрат 4т_Шток", + "Бутылочный домкрат 4т_Вентиль", + ], + "Бутылочный домкрат 4т_Тяга": [ + "Бутылочный домкрат 4т_Гильза", + "Бутылочный домкрат 4т_Тяга001", + "Бутылочный домкрат 4т_Коромысло", + ], + "Бутылочный домкрат 4т_Тяга001": [ + "Бутылочный домкрат 4т_Гильза", + "Бутылочный домкрат 4т_Тяга", + "Бутылочный домкрат 4т_Коромысло", + ], + "Бутылочный домкрат 4т_Шток насоса": [ + "Бутылочный домкрат 4т_Гильза", + "Бутылочный домкрат 4т_Коромысло", + ], + "Бутылочный домкрат 4т_Коромысло": [ + "Бутылочный домкрат 4т_Тяга", + "Бутылочный домкрат 4т_Тяга001", + "Бутылочный домкрат 4т_Шток насоса", + ], + "Бутылочный домкрат 4т_Шток": [ + "Бутылочный домкрат 4т_Гильза", + "Бутылочный домкрат 4т_Винт штока", + ], + "Бутылочный домкрат 4т_Винт штока": ["Бутылочный домкрат 4т_Шток"], + "Бутылочный домкрат 4т_Вентиль": ["Бутылочный домкрат 4т_Гильза"], + } + ), + execComposition=lambda _: ( + CheckObjectHasTouchesUseCase() + .call(0) + .either( + leftF=lambda matrix: matrix.matrixToFileSystem(outFolder), + rightF=lambda error: print(error), + ) + ), + documentPath=mocksFolder + "bottle_jack.FCStd", + modelName=AdjacencyMatrix.fileName, + model=AdjacencyMatrix, + ) + + FreeCadASPGenerationTestController( + "test adjacency matrix keys vs allparts" + ).test( + assertFn=lambda model: CoreDict(model.matrix).isMatchByKeys( + ["Куб", "Куб001"] + ), + execComposition=lambda _: ( + CheckObjectHasTouchesUseCase() + .call(0) + .either( + leftF=lambda matrix: matrix.matrixToFileSystem(outFolder), + rightF=lambda error: print(error), + ) + ), + documentPath=mocksFolder + "simple_assembly_with_two_cubes.FCStd", + modelName=AdjacencyMatrix.fileName, + model=AdjacencyMatrix, + ) + + ExitFreeCadUseCase.call() + except: + print("test error") + ExitFreeCadUseCase.call() + pass + + +test() + + +# TODO: +# 1. diff --git a/geometric_feasibility_predicate/mocks/bottle_jack.FCStd b/geometric_feasibility_predicate/mocks/bottle_jack.FCStd new file mode 100644 index 0000000..bc5fedd Binary files /dev/null and b/geometric_feasibility_predicate/mocks/bottle_jack.FCStd differ diff --git a/geometric_feasibility_predicate/mocks/simple_assembly_with_two_cubes.FCStd b/geometric_feasibility_predicate/mocks/simple_assembly_with_two_cubes.FCStd new file mode 100644 index 0000000..ef62c1f Binary files /dev/null and b/geometric_feasibility_predicate/mocks/simple_assembly_with_two_cubes.FCStd differ diff --git a/test_models/asm_reductor.FCStd b/test_models/asm_reductor.FCStd new file mode 100644 index 0000000..51d828c Binary files /dev/null and b/test_models/asm_reductor.FCStd differ diff --git a/test_models/desk_table.FCStd b/test_models/desk_table.FCStd new file mode 100644 index 0000000..8b3c384 Binary files /dev/null and b/test_models/desk_table.FCStd differ diff --git a/test_models/table_pc.FCStd b/test_models/table_pc.FCStd new file mode 100644 index 0000000..ce0788f Binary files /dev/null and b/test_models/table_pc.FCStd differ diff --git a/test_models/test_reductor.FCStd b/test_models/test_reductor.FCStd new file mode 100644 index 0000000..3f7a732 Binary files /dev/null and b/test_models/test_reductor.FCStd differ