Better handling of degenerate convex hull cases.

Contributes to CURA-1504
This commit is contained in:
Simon Edwards 2016-05-26 14:39:22 +02:00
parent 7e3dd3d443
commit 5f638f6e69
2 changed files with 42 additions and 38 deletions

View file

@ -130,46 +130,48 @@ class ConvexHullDecorator(SceneNodeDecorator):
return rounded_hull return rounded_hull
else: else:
if not self._node.getMeshData(): rounded_hull = None
return None if self._node.getMeshData():
mesh = self._node.getMeshData() mesh = self._node.getMeshData()
world_transform = self._node.getWorldTransformation() world_transform = self._node.getWorldTransformation()
# Check the cache # Check the cache
if mesh is self._2d_convex_hull_mesh and world_transform == self._2d_convex_hull_mesh_world_transform: 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') # Logger.log('d', 'Cache hit in _compute2DConvexHull mesh path')
return self._2d_convex_hull_mesh_result return self._2d_convex_hull_mesh_result
vertex_data = mesh.getConvexHullTransformedVertices(world_transform) vertex_data = mesh.getConvexHullTransformedVertices(world_transform)
# Don't use data below 0. # Don't use data below 0.
# TODO; We need a better check for this as this gives poor results for meshes with long edges. # 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 = vertex_data[vertex_data[:,1] >= 0]
# Round the vertex data to 1/10th of a mm, then remove all duplicate vertices if len(vertex_data) >= 4:
# This is done to greatly speed up further convex hull calculations as the convex hull # Round the vertex data to 1/10th of a mm, then remove all duplicate vertices
# becomes much less complex when dealing with highly detailed models. # This is done to greatly speed up further convex hull calculations as the convex hull
vertex_data = numpy.round(vertex_data, 1) # 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. # Grab the set of unique points.
# #
# This basically finds the unique rows in the array by treating them as opaque groups of bytes # 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. # 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 # See http://stackoverflow.com/questions/16970982/find-unique-rows-in-numpy-array
vertex_byte_view = numpy.ascontiguousarray(vertex_data).view( vertex_byte_view = numpy.ascontiguousarray(vertex_data).view(
numpy.dtype((numpy.void, vertex_data.dtype.itemsize * vertex_data.shape[1]))) numpy.dtype((numpy.void, vertex_data.dtype.itemsize * vertex_data.shape[1])))
_, idx = numpy.unique(vertex_byte_view, return_index=True) _, idx = numpy.unique(vertex_byte_view, return_index=True)
vertex_data = vertex_data[idx] # Select the unique rows by index. 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 if len(vertex_data) >= 4:
convex_hull = hull.getConvexHull() # 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. # 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. # 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))) 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 # Store the result in the cache
self._2d_convex_hull_mesh = mesh self._2d_convex_hull_mesh = mesh

View file

@ -39,9 +39,10 @@ class ConvexHullNode(SceneNode):
self._convex_hull_head_mesh = None self._convex_hull_head_mesh = None
self._hull = hull self._hull = hull
hull_mesh = self.createHullMesh(self._hull.getPoints()) if self._hull:
if hull_mesh: hull_mesh = self.createHullMesh(self._hull.getPoints())
self.setMeshData(hull_mesh) if hull_mesh:
self.setMeshData(hull_mesh)
convex_hull_head = self._node.callDecoration("getConvexHullHead") convex_hull_head = self._node.callDecoration("getConvexHullHead")
if convex_hull_head: if convex_hull_head:
self._convex_hull_head_mesh = self.createHullMesh(convex_hull_head.getPoints()) 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) self._shader.setUniformValue("u_color", self._color)
if self.getParent(): if self.getParent():
renderer.queueNode(self, transparent = True, shader = self._shader, backface_cull = True, sort = -8) if self.getMeshData():
if self._convex_hull_head_mesh: renderer.queueNode(self, transparent = True, shader = self._shader, backface_cull = True, sort = -8)
renderer.queueNode(self, shader = self._shader, transparent = True, mesh = self._convex_hull_head_mesh, 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 return True