12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- from typing import List, Dict
- from cura.Scene.CuraSceneNode import CuraSceneNode
- class HitChecker:
- """Checks if nodes can be printed without causing any collisions and interference"""
- def __init__(self, nodes: List[CuraSceneNode]) -> None:
- self._hit_map = self._buildHitMap(nodes)
- def anyTwoNodesBlockEachOther(self, nodes: List[CuraSceneNode]) -> bool:
- """Returns True if any 2 nodes block each other"""
- for a in nodes:
- for b in nodes:
- if self._hit_map[a][b] and self._hit_map[b][a]:
- return True
- return False
- def canPrintBefore(self, node: CuraSceneNode, other_nodes: List[CuraSceneNode]) -> bool:
- """Returns True if node doesn't block other_nodes and can be printed before them"""
- no_hits = all(not self._hit_map[node][other_node] for other_node in other_nodes)
- return no_hits
- def canPrintAfter(self, node: CuraSceneNode, other_nodes: List[CuraSceneNode]) -> bool:
- """Returns True if node doesn't hit other nodes and can be printed after them"""
- no_hits = all(not self._hit_map[other_node][node] for other_node in other_nodes)
- return no_hits
- def calculateScore(self, a: CuraSceneNode, b: CuraSceneNode) -> int:
- """Calculate score simply sums the number of other objects it 'blocks'
- :param a: node
- :param b: node
- :return: sum of the number of other objects
- """
- score_a = sum(self._hit_map[a].values())
- score_b = sum(self._hit_map[b].values())
- return score_a - score_b
- def canPrintNodesInProvidedOrder(self, ordered_nodes: List[CuraSceneNode]) -> bool:
- """Returns True If nodes don't have any hits in provided order"""
- for node_index, node in enumerate(ordered_nodes):
- nodes_before = ordered_nodes[:node_index - 1] if node_index - 1 >= 0 else []
- nodes_after = ordered_nodes[node_index + 1:] if node_index + 1 < len(ordered_nodes) else []
- if not self.canPrintBefore(node, nodes_after) or not self.canPrintAfter(node, nodes_before):
- return False
- return True
- @staticmethod
- def _buildHitMap(nodes: List[CuraSceneNode]) -> Dict[CuraSceneNode, CuraSceneNode]:
- """Pre-computes all hits between all objects
- :nodes: nodes that need to be checked for collisions
- :return: dictionary where hit_map[node1][node2] is False if there node1 can be printed before node2
- """
- hit_map = {j: {i: HitChecker._checkHit(j, i) for i in nodes} for j in nodes}
- return hit_map
- @staticmethod
- def _checkHit(a: CuraSceneNode, b: CuraSceneNode) -> bool:
- """Checks if a can be printed before b
- :param a: node
- :param b: node
- :return: False if a can be printed before b
- """
- if a == b:
- return False
- a_hit_hull = a.callDecoration("getConvexHullBoundary")
- b_hit_hull = b.callDecoration("getConvexHullHeadFull")
- overlap = a_hit_hull.intersectsPolygon(b_hit_hull)
- if overlap:
- return True
- # Adhesion areas must never overlap, regardless of printing order
- # This would cause over-extrusion
- a_hit_hull = a.callDecoration("getAdhesionArea")
- b_hit_hull = b.callDecoration("getAdhesionArea")
- overlap = a_hit_hull.intersectsPolygon(b_hit_hull)
- if overlap:
- return True
- else:
- return False
|