def test_intersectConvexHull(self, data): p1 = Polygon(numpy.array(data["p1"])) p2 = Polygon(numpy.array(data["p2"])) result = p1.intersectionConvexHulls(p2) assert len(result.getPoints()) == len( data["answer"]) #Same amount of vertices. isCorrect = False for rotation in range( 0, len(result.getPoints()) ): #The order of vertices doesn't matter, so rotate the result around and if any check succeeds, the answer is correct. thisCorrect = True #Is this rotation correct? for vertex in range(0, len(result.getPoints())): for dimension in range(0, len(result.getPoints()[vertex])): if not Float.fuzzyCompare( result.getPoints()[vertex][dimension], data["answer"][vertex][dimension]): thisCorrect = False break #Break out of two loops. if not thisCorrect: break if thisCorrect: #All vertices checked and it's still correct. isCorrect = True break result.setPoints( numpy.roll(result.getPoints(), 1, axis=0)) #Perform the rotation for the next check. assert isCorrect
def _getHeadAndFans(self) -> Polygon: if not self._global_stack: return Polygon() polygon = Polygon(numpy.array(self._global_stack.getHeadAndFansCoordinates(), numpy.float32)) offset_x = self._getSettingProperty("machine_nozzle_offset_x", "value") offset_y = self._getSettingProperty("machine_nozzle_offset_y", "value") return polygon.translate(-offset_x, -offset_y)
def test_translate(self): polygon = Polygon( numpy.array([[0.0, 0.0], [2.0, 0.0], [1.0, 2.0]], numpy.float32)) translated_poly = polygon.translate(2, 3) result = Polygon( numpy.array([[2.0, 3.0], [4.0, 3.0], [3.0, 5.0]], numpy.float32)) assert result == translated_poly
def run(self): if not self._node: return ## If the scene node is a group, use the hull of the children to calculate its hull. if self._node.callDecoration("isGroup"): hull = Polygon(numpy.zeros((0, 2), dtype=numpy.int32)) for child in self._node.getChildren(): child_hull = child.callDecoration("getConvexHull") if child_hull: hull.setPoints(numpy.append(hull.getPoints(), child_hull.getPoints(), axis = 0)) if hull.getPoints().size < 3: self._node.callDecoration("setConvexHull", None) self._node.callDecoration("setConvexHullJob", None) return Job.yieldThread() else: if not self._node.getMeshData(): return mesh = self._node.getMeshData() vertex_data = mesh.getTransformed(self._node.getWorldTransformation()).getVertices() # Don't use data below 0. TODO; We need a better check for this as this gives poor results for meshes with long edges. vertex_data = vertex_data[vertex_data[:,1]>0] hull = Polygon(numpy.rint(vertex_data[:, [0, 2]]).astype(int)) # First, calculate the normal convex hull around the points hull = hull.getConvexHull() # Then, do a Minkowski hull with a simple 1x1 quad to outset and round the normal convex hull. # This is done because of rounding errors. hull = hull.getMinkowskiHull(Polygon(numpy.array([[-1, -1], [-1, 1], [1, 1], [1, -1]], numpy.float32))) profile = Application.getInstance().getMachineManager().getActiveProfile() if profile: if profile.getSettingValue("print_sequence") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"): # Printing one at a time and it's not an object in a group self._node.callDecoration("setConvexHullBoundary", copy.deepcopy(hull)) head_hull = hull.getMinkowskiHull(Polygon(numpy.array(profile.getSettingValue("machine_head_with_fans_polygon"),numpy.float32))) self._node.callDecoration("setConvexHullHead", head_hull) hull = hull.getMinkowskiHull(Polygon(numpy.array(profile.getSettingValue("machine_head_polygon"),numpy.float32))) else: self._node.callDecoration("setConvexHullHead", None) hull_node = ConvexHullNode.ConvexHullNode(self._node, hull, Application.getInstance().getController().getScene().getRoot()) self._node.callDecoration("setConvexHullNode", hull_node) self._node.callDecoration("setConvexHull", hull) self._node.callDecoration("setConvexHullJob", None) if self._node.getParent().callDecoration("isGroup"): job = self._node.getParent().callDecoration("getConvexHullJob") if job: job.cancel() self._node.getParent().callDecoration("setConvexHull", None) hull_node = self._node.getParent().callDecoration("getConvexHullNode") if hull_node: hull_node.setParent(None)
def verifyIntersection(self, p1, p2, required_result): for n in range(0, 4): for m in range(0, 4): result = p1.intersectsPolygon(p2) self.assertEqual(result, required_result) p2 = Polygon( numpy.concatenate( (p2.getPoints()[1:], p2.getPoints()[0:1]))) p1 = Polygon( numpy.concatenate((p1.getPoints()[1:], p1.getPoints()[0:1])))
def _add2DAdhesionMargin(self, poly): # Compensate for raft/skirt/brim # Add extra margin depending on adhesion type adhesion_type = self._global_stack.getProperty("adhesion_type", "value") extra_margin = 0 machine_head_coords = numpy.array( self._global_stack.getProperty("machine_head_with_fans_polygon", "value"), numpy.float32) head_y_size = abs(machine_head_coords).min() # safe margin to take off in all directions if adhesion_type == "raft": extra_margin = max(0, self._global_stack.getProperty("raft_margin", "value") - head_y_size) elif adhesion_type == "brim": extra_margin = max(0, self._global_stack.getProperty("brim_width", "value") - head_y_size) elif adhesion_type == "skirt": extra_margin = max( 0, self._global_stack.getProperty("skirt_gap", "value") + self._global_stack.getProperty("skirt_line_count", "value") * self._global_stack.getProperty("skirt_brim_line_width", "value") - head_y_size) # adjust head_and_fans with extra margin if extra_margin > 0: # In Cura 2.2+, there is a function to create this circle-like polygon. extra_margin_polygon = Polygon(numpy.array([ [-extra_margin, 0], [-extra_margin * 0.707, extra_margin * 0.707], [0, extra_margin], [extra_margin * 0.707, extra_margin * 0.707], [extra_margin, 0], [extra_margin * 0.707, -extra_margin * 0.707], [0, -extra_margin], [-extra_margin * 0.707, -extra_margin * 0.707] ], numpy.float32)) poly = poly.getMinkowskiHull(extra_margin_polygon) return poly
def fromNode(cls, node, min_offset, scale=1): transform = node._transformation transform_x = transform._data[0][3] transform_y = transform._data[2][3] arrange_align = Preferences.getInstance().getValue( "mesh/arrange_align") if arrange_align: bb = node.getBoundingBox() bb_points = numpy.array( [[bb.right, bb.back], [bb.left, bb.back], [bb.left, bb.front], [bb.right, bb.front]], dtype=numpy.float32) polygon = Polygon(bb_points) else: hull_verts = node.callDecoration("getConvexHull") # If a model is too small then it will not contain any points if hull_verts is None or not hull_verts.getPoints().any(): return None, None # For one_at_a_time printing you need the convex hull head. polygon = node.callDecoration("getConvexHullHead") or hull_verts offset_verts = polygon.getMinkowskiHull( Polygon.approximatedCircle(min_offset)) offset_points = copy.deepcopy(offset_verts._points) # x, y offset_points[:, 0] = numpy.add(offset_points[:, 0], -transform_x) offset_points[:, 1] = numpy.add(offset_points[:, 1], -transform_y) offset_shape_arr = ShapeArray.fromPolygon(offset_points, scale=scale) hull_points = copy.deepcopy(polygon._points) hull_points[:, 0] = numpy.add(hull_points[:, 0], -transform_x) hull_points[:, 1] = numpy.add(hull_points[:, 1], -transform_y) hull_shape_arr = ShapeArray.fromPolygon(hull_points, scale=scale) return offset_shape_arr, hull_shape_arr
def _onActiveMachineChanged(self): machine = self.getActiveMachine() if machine: Preferences.getInstance().setValue("cura/active_machine", machine.getName()) self._volume.setWidth( machine.getSettingValueByKey("machine_width")) self._volume.setHeight( machine.getSettingValueByKey("machine_height")) self._volume.setDepth( machine.getSettingValueByKey("machine_depth")) disallowed_areas = machine.getSettingValueByKey( "machine_disallowed_areas") areas = [] if disallowed_areas: for area in disallowed_areas: areas.append(Polygon(numpy.array(area, numpy.float32))) self._volume.setDisallowedAreas(areas) self._volume.rebuild() offset = machine.getSettingValueByKey("machine_platform_offset") if offset: self._platform.setPosition( Vector(offset[0], offset[1], offset[2])) else: self._platform.setPosition(Vector(0.0, 0.0, 0.0))
def _add2DAdhesionMargin(self, poly: Polygon) -> Polygon: if not self._global_stack: return Polygon() # Compensate for raft/skirt/brim # Add extra margin depending on adhesion type adhesion_type = self._global_stack.getProperty("adhesion_type", "value") if adhesion_type == "raft": extra_margin = max( 0, self._getSettingProperty("raft_margin", "value")) elif adhesion_type == "brim": extra_margin = max( 0, self._getSettingProperty("brim_line_count", "value") * self._getSettingProperty("skirt_brim_line_width", "value")) elif adhesion_type == "none": extra_margin = 0 elif adhesion_type == "skirt": extra_margin = max( 0, self._getSettingProperty("skirt_gap", "value") + self._getSettingProperty("skirt_line_count", "value") * self._getSettingProperty("skirt_brim_line_width", "value")) else: raise Exception( "Unknown bed adhesion type. Did you forget to update the convex hull calculations for your new bed adhesion type?" ) # Adjust head_and_fans with extra margin if extra_margin > 0: extra_margin_polygon = Polygon.approximatedCircle(extra_margin) poly = poly.getMinkowskiHull(extra_margin_polygon) return poly
def test_compute2DConvexHullNoMeshData(convex_hull_decorator): node = SceneNode() with patch("UM.Application.Application.getInstance", MagicMock(return_value=mocked_application)): convex_hull_decorator.setNode(node) assert convex_hull_decorator._compute2DConvexHull() == Polygon([])
def _computeDisallowedAreasPrinted(self, used_extruders): result = {} for extruder in used_extruders: result[extruder.getId()] = [] #Currently, the only normally printed object is the prime tower. if ExtruderManager.getInstance().getResolveOrValue("prime_tower_enable") == True: prime_tower_size = self._global_container_stack.getProperty("prime_tower_size", "value") machine_width = self._global_container_stack.getProperty("machine_width", "value") machine_depth = self._global_container_stack.getProperty("machine_depth", "value") prime_tower_x = self._global_container_stack.getProperty("prime_tower_position_x", "value") prime_tower_y = - self._global_container_stack.getProperty("prime_tower_position_y", "value") if not self._global_container_stack.getProperty("machine_center_is_zero", "value"): prime_tower_x = prime_tower_x - machine_width / 2 #Offset by half machine_width and _depth to put the origin in the front-left. prime_tower_y = prime_tower_y + machine_depth / 2 prime_tower_area = Polygon([ [prime_tower_x - prime_tower_size, prime_tower_y - prime_tower_size], [prime_tower_x, prime_tower_y - prime_tower_size], [prime_tower_x, prime_tower_y], [prime_tower_x - prime_tower_size, prime_tower_y], ]) prime_tower_area = prime_tower_area.getMinkowskiHull(Polygon.approximatedCircle(0)) for extruder in used_extruders: result[extruder.getId()].append(prime_tower_area) #The prime tower location is the same for each extruder, regardless of offset. return result
def _offsetHull(self, convex_hull: Polygon) -> Polygon: """Offset the convex hull with settings that influence the collision area. :param convex_hull: Polygon of the original convex hull. :return: New Polygon instance that is offset with everything that influences the collision area. """ horizontal_expansion = max( self._getSettingProperty("xy_offset", "value"), self._getSettingProperty("xy_offset_layer_0", "value")) mold_width = 0 if self._getSettingProperty("mold_enabled", "value"): mold_width = self._getSettingProperty("mold_width", "value") hull_offset = horizontal_expansion + mold_width if hull_offset > 0: #TODO: Implement Minkowski subtraction for if the offset < 0. expansion_polygon = Polygon( numpy.array( [[-hull_offset, -hull_offset], [-hull_offset, hull_offset], [hull_offset, hull_offset], [hull_offset, -hull_offset]], numpy.float32)) return convex_hull.getMinkowskiHull(expansion_polygon) else: return convex_hull
def getConvexHull(self): if self._node is None: return None if getattr(self._node, "_non_printing_mesh", False): # infill_mesh, cutting_mesh and anti_overhang_mesh do not need a convex hull # node._non_printing_mesh is set in SettingOverrideDecorator return None hull = self._compute2DConvexHull() if self._global_stack and self._node: # Parent can be None if node is just loaded. if self._global_stack.getProperty( "print_sequence", "value") == "one_at_a_time" and ( self._node.getParent() is None or not self._node.getParent().callDecoration("isGroup")): hull = hull.getMinkowskiHull( Polygon( numpy.array( self._global_stack.getProperty( "machine_head_polygon", "value"), numpy.float32))) hull = self._add2DAdhesionMargin(hull) return hull
def test_intersectsPolygon(self): p1 = Polygon( numpy.array([[0, 0], [10, 0], [10, 10], [0, 10]], numpy.float32)) p2 = Polygon( numpy.array([[5, 0], [15, 0], [15, 10], [5, 10]], numpy.float32)) self.verifyIntersection(p1, p2, (-5.0, 0.0)) p2 = Polygon( numpy.array([[-5, 0], [5, 0], [5, 10], [-5, 10]], numpy.float32)) self.verifyIntersection(p1, p2, (5.0, 0.0)) p2 = Polygon( numpy.array([[0, 5], [10, 5], [10, 15], [0, 15]], numpy.float32)) self.verifyIntersection(p1, p2, (0.0, -5.0)) p2 = Polygon( numpy.array([[0, -5], [10, -5], [10, 5], [0, 5]], numpy.float32)) self.verifyIntersection(p1, p2, (0.0, 5.0)) p2 = Polygon( numpy.array([[5, 5], [15, -5], [30, 5], [15, 15]], numpy.float32)) self.verifyIntersection(p1, p2, (-5.0, 0.0)) p2 = Polygon( numpy.array([[15, 0], [25, 0], [25, 10], [15, 10]], numpy.float32)) self.verifyIntersection(p1, p2, None)
def _offsetHull(self, convex_hull): horizontal_expansion = max(0.5, self._getSettingProperty("xy_offset", "value")) expansion_polygon = Polygon(numpy.array([ [-horizontal_expansion, -horizontal_expansion], [-horizontal_expansion, horizontal_expansion], [horizontal_expansion, horizontal_expansion], [horizontal_expansion, -horizontal_expansion] ], numpy.float32)) return convex_hull.getMinkowskiHull(expansion_polygon)
def run(self): if not self._node or not self._node.getMeshData(): return mesh = self._node.getMeshData() vertexData = mesh.getTransformed(self._node.getWorldTransformation()).getVertices() hull = Polygon(numpy.rint(vertexData[:, [0, 2]]).astype(int)) # First, calculate the normal convex hull around the points hull = hull.getConvexHull() # Then, do a Minkowski hull with a simple 1x1 quad to outset and round the normal convex hull. hull = hull.getMinkowskiHull(Polygon(numpy.array([[-1, -1], [-1, 1], [1, 1], [1, -1]], numpy.float32))) hull_node = ConvexHullNode.ConvexHullNode(self._node, hull, Application.getInstance().getController().getScene().getRoot()) self._node._convex_hull = hull delattr(self._node, "_convex_hull_job")
def test_mirror(self, data): polygon = Polygon(numpy.array(data["points"], numpy.float32)) #Create a polygon with the specified points. polygon.mirror(data["axis_point"], data["axis_direction"]) #Mirror over the specified axis. points = polygon.getPoints() assert len(points) == len(data["points"]) #Must have the same amount of vertices. for point_index in range(len(points)): assert len(points[point_index]) == len(data["answer"][point_index]) #Same dimensionality (2). for dimension in range(len(points[point_index])): assert Float.fuzzyCompare(points[point_index][dimension], data["answer"][point_index][dimension]) #All points must be equal.
def fromNode( cls, node: "SceneNode", min_offset: float, scale: float = 0.5, include_children: bool = False ) -> Tuple[Optional["ShapeArray"], Optional["ShapeArray"]]: """Instantiate an offset and hull ShapeArray from a scene node. :param node: source node where the convex hull must be present :param min_offset: offset for the offset ShapeArray :param scale: scale the coordinates :return: A tuple containing an offset and hull shape array """ transform = node._transformation transform_x = transform._data[0][3] transform_y = transform._data[2][3] hull_verts = node.callDecoration("getConvexHull") # If a model is too small then it will not contain any points if hull_verts is None or not hull_verts.getPoints().any(): return None, None # For one_at_a_time printing you need the convex hull head. hull_head_verts = node.callDecoration( "getConvexHullHead") or hull_verts if hull_head_verts is None: hull_head_verts = Polygon() # If the child-nodes are included, adjust convex hulls as well: if include_children: children = node.getAllChildren() if not children is None: for child in children: # 'Inefficient' combination of convex hulls through known code rather than mess it up: child_hull = child.callDecoration("getConvexHull") if not child_hull is None: hull_verts = hull_verts.unionConvexHulls(child_hull) child_hull_head = child.callDecoration( "getConvexHullHead") or child_hull if not child_hull_head is None: hull_head_verts = hull_head_verts.unionConvexHulls( child_hull_head) offset_verts = hull_head_verts.getMinkowskiHull( Polygon.approximatedCircle(min_offset)) offset_points = copy.deepcopy(offset_verts._points) # x, y offset_points[:, 0] = numpy.add(offset_points[:, 0], -transform_x) offset_points[:, 1] = numpy.add(offset_points[:, 1], -transform_y) offset_shape_arr = ShapeArray.fromPolygon(offset_points, scale=scale) hull_points = copy.deepcopy(hull_verts._points) hull_points[:, 0] = numpy.add(hull_points[:, 0], -transform_x) hull_points[:, 1] = numpy.add(hull_points[:, 1], -transform_y) hull_shape_arr = ShapeArray.fromPolygon(hull_points, scale=scale) # x, y return offset_shape_arr, hull_shape_arr
def test_parts_of_fromNode2(): from UM.Math.Polygon import Polygon p = Polygon(numpy.array([[-2, -2], [2, -2], [2, 2], [-2, 2]], dtype=numpy.int32) * 2) # 4x4 offset = 13.3 scale = 0.5 p_offset = p.getMinkowskiHull(Polygon.approximatedCircle(offset)) shape_arr1 = ShapeArray.fromPolygon(p._points, scale = scale) shape_arr2 = ShapeArray.fromPolygon(p_offset._points, scale = scale) assert shape_arr1.arr.shape[0] >= (4 * scale) - 1 # -1 is to account for rounding errors assert shape_arr2.arr.shape[0] >= (2 * offset + 4) * scale - 1
def getConvexHull(self): if self._node is None: return None hull = self._compute2DConvexHull() if self._global_stack and self._node: if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"): hull = hull.getMinkowskiHull(Polygon(numpy.array(self._global_stack.getProperty("machine_head_polygon", "value"), numpy.float32))) return hull
def test_parts_of_fromNode(): from UM.Math.Polygon import Polygon p = Polygon( numpy.array([[-2, -2], [2, -2], [2, 2], [-2, 2]], dtype=numpy.int32)) offset = 1 p_offset = p.getMinkowskiHull(Polygon.approximatedCircle(offset)) assert len(numpy.where(p_offset._points[:, 0] >= 2.9)) > 0 assert len(numpy.where(p_offset._points[:, 0] <= -2.9)) > 0 assert len(numpy.where(p_offset._points[:, 1] >= 2.9)) > 0 assert len(numpy.where(p_offset._points[:, 1] <= -2.9)) > 0
def test_project(self, data): p = Polygon(numpy.array([ [0.0, 1.0], [1.0, 1.0], [1.0, 2.0], [0.0, 2.0] ], numpy.float32)) result = p.project(data["normal"]) #Project the polygon onto the specified normal vector. assert len(result) == len(data["answer"]) #Same dimensionality (2). for dimension in range(len(result)): assert Float.fuzzyCompare(result[dimension], data["answer"][dimension])
def getConvexHull(self): if self._node is None: return None hull = self._compute2DConvexHull() if self._global_stack and self._node: # Parent can be None if node is just loaded. if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and (self._node.getParent() is None or not self._node.getParent().callDecoration("isGroup")): hull = hull.getMinkowskiHull(Polygon(numpy.array(self._global_stack.getProperty("machine_head_polygon", "value"), numpy.float32))) hull = self._add2DAdhesionMargin(hull) return hull
def test_parts_of_fromNode(): """Just adding some stuff to ensure fromNode works as expected. Some parts should actually be in UM""" from UM.Math.Polygon import Polygon p = Polygon( numpy.array([[-2, -2], [2, -2], [2, 2], [-2, 2]], dtype=numpy.int32)) offset = 1 p_offset = p.getMinkowskiHull(Polygon.approximatedCircle(offset)) assert len(numpy.where(p_offset._points[:, 0] >= 2.9)) > 0 assert len(numpy.where(p_offset._points[:, 0] <= -2.9)) > 0 assert len(numpy.where(p_offset._points[:, 1] >= 2.9)) > 0 assert len(numpy.where(p_offset._points[:, 1] <= -2.9)) > 0
def test_intersectsPolygon(self, data): p1 = Polygon(numpy.array([ #The base polygon to intersect with. [ 0, 0], [10, 0], [10, 10], [ 0, 10] ], numpy.float32)) p2 = Polygon(numpy.array(data["polygon"])) #The parametrised polygon to intersect with. #Shift the order of vertices in both polygons around. The outcome should be independent of what the first vertex is. for n in range(0, len(p1.getPoints())): for m in range(0, len(data["polygon"])): result = p1.intersectsPolygon(p2) if not data["answer"]: #Result should be None. assert result == None else: assert result != None for i in range(0, len(data["answer"])): assert Float.fuzzyCompare(result[i], data["answer"][i]) p2.setPoints(numpy.roll(p2.getPoints(), 1, axis = 0)) #Shift p2. p1.setPoints(numpy.roll(p1.getPoints(), 1, axis = 0)) #Shift p1.
def test_computeDisalowedAreasStaticSingleExtruder(self, build_volume: BuildVolume): mocked_stack = MagicMock() mocked_stack.getProperty = MagicMock(side_effect=self.getPropertySideEffect) mocked_extruder = MagicMock() mocked_extruder.getProperty = MagicMock(side_effect=self.getPropertySideEffect) mocked_extruder.getId = MagicMock(return_value = "zomg") build_volume._global_container_stack = mocked_stack with patch("cura.Settings.ExtruderManager.ExtruderManager.getInstance"): result = build_volume._computeDisallowedAreasStatic(0, [mocked_extruder]) assert result == {"zomg": [Polygon([[-84.0, 102.5], [-115.0, 102.5], [-200.0, 112.5], [-82.0, 112.5]])]}
def _updateDisallowedAreas(self): if not self._active_container_stack: return disallowed_areas = self._active_container_stack.getProperty("machine_disallowed_areas", "value") areas = [] skirt_size = self._getSkirtSize(self._active_container_stack) if disallowed_areas: # Extend every area already in the disallowed_areas with the skirt size. for area in disallowed_areas: poly = Polygon(numpy.array(area, numpy.float32)) poly = poly.getMinkowskiHull(Polygon(numpy.array([ [-skirt_size, 0], [-skirt_size * 0.707, skirt_size * 0.707], [0, skirt_size], [skirt_size * 0.707, skirt_size * 0.707], [skirt_size, 0], [skirt_size * 0.707, -skirt_size * 0.707], [0, -skirt_size], [-skirt_size * 0.707, -skirt_size * 0.707] ], numpy.float32))) areas.append(poly) # Add the skirt areas around the borders of the build plate. if skirt_size > 0: half_machine_width = self._active_container_stack.getProperty("machine_width", "value") / 2 half_machine_depth = self._active_container_stack.getProperty("machine_depth", "value") / 2 areas.append(Polygon(numpy.array([ [-half_machine_width, -half_machine_depth], [-half_machine_width, half_machine_depth], [-half_machine_width + skirt_size, half_machine_depth - skirt_size], [-half_machine_width + skirt_size, -half_machine_depth + skirt_size] ], numpy.float32))) areas.append(Polygon(numpy.array([ [half_machine_width, half_machine_depth], [half_machine_width, -half_machine_depth], [half_machine_width - skirt_size, -half_machine_depth + skirt_size], [half_machine_width - skirt_size, half_machine_depth - skirt_size] ], numpy.float32))) areas.append(Polygon(numpy.array([ [-half_machine_width, half_machine_depth], [half_machine_width, half_machine_depth], [half_machine_width - skirt_size, half_machine_depth - skirt_size], [-half_machine_width + skirt_size, half_machine_depth - skirt_size] ], numpy.float32))) areas.append(Polygon(numpy.array([ [half_machine_width, -half_machine_depth], [-half_machine_width, -half_machine_depth], [-half_machine_width + skirt_size, -half_machine_depth + skirt_size], [half_machine_width - skirt_size, -half_machine_depth + skirt_size] ], numpy.float32))) self._disallowed_areas = areas
def _updateDisallowedAreas(self): if not self._active_instance or not self._active_profile: return disallowed_areas = self._active_instance.getMachineSettingValue("machine_disallowed_areas") areas = [] skirt_size = 0.0 if self._active_profile: skirt_size = self._getSkirtSize(self._active_profile) if disallowed_areas: for area in disallowed_areas: poly = Polygon(numpy.array(area, numpy.float32)) poly = poly.getMinkowskiHull(Polygon(numpy.array([ [-skirt_size, 0], [-skirt_size * 0.707, skirt_size * 0.707], [0, skirt_size], [skirt_size * 0.707, skirt_size * 0.707], [skirt_size, 0], [skirt_size * 0.707, -skirt_size * 0.707], [0, -skirt_size], [-skirt_size * 0.707, -skirt_size * 0.707] ], numpy.float32))) areas.append(poly) if skirt_size > 0: half_machine_width = self._active_instance.getMachineSettingValue("machine_width") / 2 half_machine_depth = self._active_instance.getMachineSettingValue("machine_depth") / 2 areas.append(Polygon(numpy.array([ [-half_machine_width, -half_machine_depth], [-half_machine_width, half_machine_depth], [-half_machine_width + skirt_size, half_machine_depth - skirt_size], [-half_machine_width + skirt_size, -half_machine_depth + skirt_size] ], numpy.float32))) areas.append(Polygon(numpy.array([ [half_machine_width, half_machine_depth], [half_machine_width, -half_machine_depth], [half_machine_width - skirt_size, -half_machine_depth + skirt_size], [half_machine_width - skirt_size, half_machine_depth - skirt_size] ], numpy.float32))) areas.append(Polygon(numpy.array([ [-half_machine_width, half_machine_depth], [half_machine_width, half_machine_depth], [half_machine_width - skirt_size, half_machine_depth - skirt_size], [-half_machine_width + skirt_size, half_machine_depth - skirt_size] ], numpy.float32))) areas.append(Polygon(numpy.array([ [half_machine_width, -half_machine_depth], [-half_machine_width, -half_machine_depth], [-half_machine_width + skirt_size, -half_machine_depth + skirt_size], [half_machine_width - skirt_size, -half_machine_depth + skirt_size] ], numpy.float32))) self._disallowed_areas = areas
def getConvexHull(self) -> Optional[Polygon]: if self._node is None: return None if self._node.callDecoration("isNonPrintingMesh"): return None hull = self._compute2DConvexHull() if self._global_stack and self._node is not None and hull is not None: # Parent can be None if node is just loaded. if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and not self.hasGroupAsParent(self._node): hull = hull.getMinkowskiHull(Polygon(numpy.array(self._global_stack.getProperty("machine_head_polygon", "value"), numpy.float32))) hull = self._add2DAdhesionMargin(hull) return hull
def test_compute2DConvexHullMeshData(convex_hull_decorator): node = SceneNode() mb = MeshBuilder() mb.addCube(10, 10, 10) node.setMeshData(mb.build()) convex_hull_decorator._getSettingProperty = MagicMock(return_value=0) with patch("UM.Application.Application.getInstance", MagicMock(return_value=mocked_application)): convex_hull_decorator.setNode(node) assert convex_hull_decorator._compute2DConvexHull() == Polygon( [[5.0, -5.0], [-5.0, -5.0], [-5.0, 5.0], [5.0, 5.0]])