API with assembly options and constraints; DFS Liaison/Adjacency matrix generation fix; add unit-tests
This commit is contained in:
parent
c64bbf4a70
commit
d2ab856d64
8 changed files with 693 additions and 148 deletions
|
@ -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": []
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
BIN
geometric_feasibility_predicate/mocks/bottle_jack.FCStd
Normal file
BIN
geometric_feasibility_predicate/mocks/bottle_jack.FCStd
Normal file
Binary file not shown.
Binary file not shown.
BIN
test_models/asm_reductor.FCStd
Normal file
BIN
test_models/asm_reductor.FCStd
Normal file
Binary file not shown.
BIN
test_models/desk_table.FCStd
Normal file
BIN
test_models/desk_table.FCStd
Normal file
Binary file not shown.
BIN
test_models/table_pc.FCStd
Normal file
BIN
test_models/table_pc.FCStd
Normal file
Binary file not shown.
BIN
test_models/test_reductor.FCStd
Normal file
BIN
test_models/test_reductor.FCStd
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue