diff --git a/ConvexHullJob.py b/ConvexHullJob.py new file mode 100644 index 0000000000..617a0a9c35 --- /dev/null +++ b/ConvexHullJob.py @@ -0,0 +1,32 @@ +from UM.Job import Job +from UM.Application import Application +from UM.Math.Polygon import Polygon + +import numpy + +from ConvexHullNode import ConvexHullNode + +class ConvexHullJob(Job): + def __init__(self, node): + super().__init__() + + self._node = node + + 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(self._node, hull, Application.getInstance().getController().getScene().getRoot()) + + self._node._convex_hull = hull + delattr(self._node, "_convex_hull_job") diff --git a/ConvexHullNode.py b/ConvexHullNode.py new file mode 100644 index 0000000000..fb760b874a --- /dev/null +++ b/ConvexHullNode.py @@ -0,0 +1,72 @@ +from UM.Scene.SceneNode import SceneNode +from UM.Resources import Resources +from UM.Math.Color import Color +from UM.Math.Vector import Vector +from UM.Mesh.MeshData import MeshData + +import numpy + +class ConvexHullNode(SceneNode): + def __init__(self, node, hull, parent = None): + super().__init__(parent) + + self.setCalculateBoundingBox(False) + + self._material = None + + self._original_parent = parent + + self._inherit_orientation = False + self._inherit_scale = False + + self._node = node + self._node.transformationChanged.connect(self._onNodePositionChanged) + self._node.parentChanged.connect(self._onNodeParentChanged) + #self._onNodePositionChanged(self._node) + + self._hull = hull + + hull_points = self._hull.getPoints() + center = (hull_points.min(0) + hull_points.max(0)) / 2.0 + + mesh = MeshData() + mesh.addVertex(center[0], 0.1, center[1]) + + for point in hull_points: + mesh.addVertex(point[0], 0.1, point[1]) + + indices = [] + for i in range(len(hull_points) - 1): + indices.append([0, i + 1, i + 2]) + + indices.append([0, mesh.getVertexCount() - 1, 1]) + + mesh.addIndices(numpy.array(indices, numpy.int32)) + + self.setMeshData(mesh) + + def render(self, renderer): + if not self._material: + self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, 'basic.vert'), Resources.getPath(Resources.ShadersLocation, 'color.frag')) + + self._material.setUniformValue('u_color', Color(35, 35, 35, 128)) + + renderer.queueNode(self, material = self._material, transparent = True) + + return True + + def _onNodePositionChanged(self, node): + #self.setPosition(node.getWorldPosition()) + if hasattr(node, "_convex_hull"): + delattr(node, "_convex_hull") + self.setParent(None) + + + #self._node.transformationChanged.disconnect(self._onNodePositionChanged) + #self._node.parentChanged.disconnect(self._onNodeParentChanged) + + def _onNodeParentChanged(self, node): + if node.getParent(): + self.setParent(self._original_parent) + else: + self.setParent(None)