From 5f638f6e69b85d64d1904bac8c4c25417294e209 Mon Sep 17 00:00:00 2001 From: Simon Edwards Date: Thu, 26 May 2016 14:39:22 +0200 Subject: [PATCH] Better handling of degenerate convex hull cases. Contributes to CURA-1504 --- cura/ConvexHullDecorator.py | 66 +++++++++++++++++++------------------ cura/ConvexHullNode.py | 14 ++++---- 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/cura/ConvexHullDecorator.py b/cura/ConvexHullDecorator.py index c42ab4f339..2a8f55d09e 100644 --- a/cura/ConvexHullDecorator.py +++ b/cura/ConvexHullDecorator.py @@ -130,46 +130,48 @@ class ConvexHullDecorator(SceneNodeDecorator): return rounded_hull else: - if not self._node.getMeshData(): - return None - mesh = self._node.getMeshData() - world_transform = self._node.getWorldTransformation() + rounded_hull = None + if self._node.getMeshData(): + mesh = self._node.getMeshData() + world_transform = self._node.getWorldTransformation() - # Check the cache - if mesh is self._2d_convex_hull_mesh and world_transform == self._2d_convex_hull_mesh_world_transform: - # Logger.log('d', 'Cache hit in _compute2DConvexHull mesh path') - return self._2d_convex_hull_mesh_result + # Check the cache + if mesh is self._2d_convex_hull_mesh and world_transform == self._2d_convex_hull_mesh_world_transform: + # Logger.log('d', 'Cache hit in _compute2DConvexHull mesh path') + return self._2d_convex_hull_mesh_result - vertex_data = mesh.getConvexHullTransformedVertices(world_transform) - # 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] + vertex_data = mesh.getConvexHullTransformedVertices(world_transform) + # 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] - # Round the vertex data to 1/10th of a mm, then remove all duplicate vertices - # This is done to greatly speed up further convex hull calculations as the convex hull - # becomes much less complex when dealing with highly detailed models. - vertex_data = numpy.round(vertex_data, 1) + if len(vertex_data) >= 4: + # Round the vertex data to 1/10th of a mm, then remove all duplicate vertices + # This is done to greatly speed up further convex hull calculations as the convex hull + # becomes much less complex when dealing with highly detailed models. + vertex_data = numpy.round(vertex_data, 1) - vertex_data = vertex_data[:, [0, 2]] # Drop the Y components to project to 2D. + vertex_data = vertex_data[:, [0, 2]] # Drop the Y components to project to 2D. - # Grab the set of unique points. - # - # This basically finds the unique rows in the array by treating them as opaque groups of bytes - # which are as long as the 2 float64s in each row, and giving this view to numpy.unique() to munch. - # See http://stackoverflow.com/questions/16970982/find-unique-rows-in-numpy-array - vertex_byte_view = numpy.ascontiguousarray(vertex_data).view( - numpy.dtype((numpy.void, vertex_data.dtype.itemsize * vertex_data.shape[1]))) - _, idx = numpy.unique(vertex_byte_view, return_index=True) - vertex_data = vertex_data[idx] # Select the unique rows by index. + # Grab the set of unique points. + # + # This basically finds the unique rows in the array by treating them as opaque groups of bytes + # which are as long as the 2 float64s in each row, and giving this view to numpy.unique() to munch. + # See http://stackoverflow.com/questions/16970982/find-unique-rows-in-numpy-array + vertex_byte_view = numpy.ascontiguousarray(vertex_data).view( + numpy.dtype((numpy.void, vertex_data.dtype.itemsize * vertex_data.shape[1]))) + _, idx = numpy.unique(vertex_byte_view, return_index=True) + vertex_data = vertex_data[idx] # Select the unique rows by index. - hull = Polygon(vertex_data) + hull = Polygon(vertex_data) - # First, calculate the normal convex hull around the points - convex_hull = hull.getConvexHull() + if len(vertex_data) >= 4: + # First, calculate the normal convex hull around the points + convex_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. - rounded_hull = convex_hull.getMinkowskiHull(Polygon(numpy.array([[-0.5, -0.5], [-0.5, 0.5], [0.5, 0.5], [0.5, -0.5]], numpy.float32))) + # 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. + rounded_hull = convex_hull.getMinkowskiHull(Polygon(numpy.array([[-0.5, -0.5], [-0.5, 0.5], [0.5, 0.5], [0.5, -0.5]], numpy.float32))) # Store the result in the cache self._2d_convex_hull_mesh = mesh diff --git a/cura/ConvexHullNode.py b/cura/ConvexHullNode.py index 3d00edd288..2d88604b6e 100644 --- a/cura/ConvexHullNode.py +++ b/cura/ConvexHullNode.py @@ -39,9 +39,10 @@ class ConvexHullNode(SceneNode): self._convex_hull_head_mesh = None self._hull = hull - hull_mesh = self.createHullMesh(self._hull.getPoints()) - if hull_mesh: - self.setMeshData(hull_mesh) + if self._hull: + hull_mesh = self.createHullMesh(self._hull.getPoints()) + if hull_mesh: + self.setMeshData(hull_mesh) convex_hull_head = self._node.callDecoration("getConvexHullHead") if convex_hull_head: self._convex_hull_head_mesh = self.createHullMesh(convex_hull_head.getPoints()) @@ -76,9 +77,10 @@ class ConvexHullNode(SceneNode): self._shader.setUniformValue("u_color", self._color) if self.getParent(): - renderer.queueNode(self, transparent = True, shader = self._shader, backface_cull = True, sort = -8) - if self._convex_hull_head_mesh: - renderer.queueNode(self, shader = self._shader, transparent = True, mesh = self._convex_hull_head_mesh, backface_cull = True, sort = -8) + if self.getMeshData(): + renderer.queueNode(self, transparent = True, shader = self._shader, backface_cull = True, sort = -8) + if self._convex_hull_head_mesh: + renderer.queueNode(self, shader = self._shader, transparent = True, mesh = self._convex_hull_head_mesh, backface_cull = True, sort = -8) return True