예제 #1
0
    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
                    
        else: 
            if not self._node.getMeshData():
                return
            mesh = self._node.getMeshData()
            vertex_data = mesh.getTransformed(self._node.getWorldTransformation()).getVertices()

            hull = Polygon(numpy.rint(vertex_data[:, [0, 2]]).astype(int))
        
        # First, calculate the normal convex hull around the points
        hull = hull.getConvexHull()
        #print("hull: " , self._node.callDecoration("isGroup"), " " , hull.getPoints())
        # 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.callDecoration("setConvexHullNode", hull_node)
        self._node.callDecoration("setConvexHull", hull)
        self._node.callDecoration("setConvexHullJob", None)
예제 #2
0
    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)
예제 #3
0
    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")
예제 #4
0
    def _compute2DConvexHull(self) -> Optional[Polygon]:
        if self._node is None:
            return None
        if self._node.callDecoration("isGroup"):
            points = numpy.zeros((0, 2), dtype=numpy.int32)
            for child in self._node.getChildren():
                child_hull = child.callDecoration("_compute2DConvexHull")
                if child_hull:
                    try:
                        points = numpy.append(points,
                                              child_hull.getPoints(),
                                              axis=0)
                    except ValueError:
                        pass

                if points.size < 3:
                    return None
            child_polygon = Polygon(points)

            # Check the cache
            if child_polygon == self._2d_convex_hull_group_child_polygon:
                return self._2d_convex_hull_group_result

            convex_hull = child_polygon.getConvexHull(
            )  #First calculate the normal convex hull around the points.
            offset_hull = self._offsetHull(
                convex_hull)  #Then apply the offset from the settings.

            # Store the result in the cache
            self._2d_convex_hull_group_child_polygon = child_polygon
            self._2d_convex_hull_group_result = offset_hull

            return offset_hull

        else:
            convex_hull = Polygon([])
            offset_hull = Polygon([])
            mesh = self._node.getMeshData()
            if mesh is None:
                return Polygon(
                    []
                )  # Node has no mesh data, so just return an empty Polygon.

            world_transform = self._node.getWorldTransformation(copy=True)

            # Check the cache
            if mesh is self._2d_convex_hull_mesh and world_transform == self._2d_convex_hull_mesh_world_transform:
                return self._offsetHull(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.
            # Do not throw away vertices: the convex hull may be too small and objects can collide.
            # vertex_data = vertex_data[vertex_data[:,1] >= -0.01]

            if vertex_data is not None and len(
                    vertex_data
            ) >= 4:  # type: ignore # mypy and numpy don't play along well just yet.
                # 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.

                # 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)

                if len(vertex_data) >= 3:
                    convex_hull = hull.getConvexHull()
                    offset_hull = self._offsetHull(convex_hull)

            # Store the result in the cache
            self._2d_convex_hull_mesh = mesh
            self._2d_convex_hull_mesh_world_transform = world_transform
            self._2d_convex_hull_mesh_result = convex_hull

            return offset_hull
예제 #5
0
    def _compute2DConvexHull(self):
        if self._node.callDecoration("isGroup"):
            points = numpy.zeros((0, 2), dtype=numpy.int32)
            for child in self._node.getChildren():
                child_hull = child.callDecoration("_compute2DConvexHull")
                if child_hull:
                    points = numpy.append(points, child_hull.getPoints(), axis = 0)

                if points.size < 3:
                    return None
            child_polygon = Polygon(points)

            # Check the cache
            if child_polygon == self._2d_convex_hull_group_child_polygon:
                return self._2d_convex_hull_group_result

            # First, calculate the normal convex hull around the points
            convex_hull = child_polygon.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 = self._roundHull(convex_hull)

            # Store the result in the cache
            self._2d_convex_hull_group_child_polygon = child_polygon
            self._2d_convex_hull_group_result = rounded_hull

            return rounded_hull

        else:
            rounded_hull = None
            mesh = None
            world_transform = 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:
                    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.
                # Do not throw away vertices: the convex hull may be too small and objects can collide.
                # vertex_data = vertex_data[vertex_data[:,1] >= -0.01]

                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.

                    # 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)

                    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)))

            # Store the result in the cache
            self._2d_convex_hull_mesh = mesh
            self._2d_convex_hull_mesh_world_transform = world_transform
            self._2d_convex_hull_mesh_result = rounded_hull

            return rounded_hull
예제 #6
0
    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]

            # 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.

            # 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)

        # 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(
                    [[-0.5, -0.5], [-0.5, 0.5], [0.5, 0.5], [0.5, -0.5]],
                    numpy.float32)))

        global_stack = Application.getInstance().getGlobalContainerStack()
        if global_stack:
            if global_stack.getProperty(
                    "print_sequence",
                    "value") == "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_and_fans = Polygon(
                    numpy.array(
                        global_stack.getProperty(
                            "machine_head_with_fans_polygon", "value"),
                        numpy.float32))

                # Full head hull is used to actually check the order.
                full_head_hull = hull.getMinkowskiHull(head_and_fans)
                self._node.callDecoration("setConvexHullHeadFull",
                                          full_head_hull)
                mirrored = copy.deepcopy(head_and_fans)
                mirrored.mirror([0, 0], [0, 1])  #Mirror horizontally.
                mirrored.mirror([0, 0], [1, 0])  #Mirror vertically.
                head_and_fans = head_and_fans.intersectionConvexHulls(mirrored)

                # Min head hull is used for the push free
                min_head_hull = hull.getMinkowskiHull(head_and_fans)
                self._node.callDecoration("setConvexHullHead", min_head_hull)
                hull = hull.getMinkowskiHull(
                    Polygon(
                        numpy.array(
                            global_stack.getProperty("machine_head_polygon",
                                                     "value"), numpy.float32)))
            else:
                self._node.callDecoration("setConvexHullHead", None)
        if self._node.getParent(
        ) is None:  # Node was already deleted before job is done.
            self._node.callDecoration("setConvexHullNode", None)
            self._node.callDecoration("setConvexHull", None)
            self._node.callDecoration("setConvexHullJob", None)
            return

        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() and 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)
예제 #7
0
    def _compute2DConvexHull(self):
        if self._node.callDecoration("isGroup"):
            points = numpy.zeros((0, 2), dtype=numpy.int32)
            for child in self._node.getChildren():
                child_hull = child.callDecoration("_compute2DConvexHull")
                if child_hull:
                    points = numpy.append(points, child_hull.getPoints(), axis = 0)

                if points.size < 3:
                    return None
            child_polygon = Polygon(points)

            # Check the cache
            if child_polygon == self._2d_convex_hull_group_child_polygon:
                return self._2d_convex_hull_group_result

            # First, calculate the normal convex hull around the points
            convex_hull = child_polygon.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 = self._roundHull(convex_hull)

            # Store the result in the cache
            self._2d_convex_hull_group_child_polygon = child_polygon
            self._2d_convex_hull_group_result = rounded_hull

            return rounded_hull

        else:
            rounded_hull = None
            mesh = None
            world_transform = 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:
                    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.
                # Do not throw away vertices: the convex hull may be too small and objects can collide.
                # vertex_data = vertex_data[vertex_data[:,1] >= -0.01]

                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.

                    # 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)

                    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)))

            # Store the result in the cache
            self._2d_convex_hull_mesh = mesh
            self._2d_convex_hull_mesh_world_transform = world_transform
            self._2d_convex_hull_mesh_result = rounded_hull

            return rounded_hull
예제 #8
0
    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]

            # 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)
            duplicates = (vertex_data[:,0] == vertex_data[:,1]) | (vertex_data[:,1] == vertex_data[:,2]) | (vertex_data[:,0] == vertex_data[:,2])
            vertex_data = numpy.delete(vertex_data, numpy.where(duplicates), axis = 0)

            hull = Polygon(vertex_data[:, [0, 2]])

        # 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([[-0.5, -0.5], [-0.5, 0.5], [0.5, 0.5], [0.5, -0.5]], numpy.float32)))

        profile = Application.getInstance().getMachineManager().getWorkingProfile()
        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_and_fans = Polygon(numpy.array(profile.getSettingValue("machine_head_with_fans_polygon"), numpy.float32))

                # Full head hull is used to actually check the order.
                full_head_hull = hull.getMinkowskiHull(head_and_fans)
                self._node.callDecoration("setConvexHullHeadFull", full_head_hull)
                mirrored = copy.deepcopy(head_and_fans)
                mirrored.mirror([0, 0], [0, 1]) #Mirror horizontally.
                mirrored.mirror([0, 0], [1, 0]) #Mirror vertically.
                head_and_fans = head_and_fans.intersectionConvexHulls(mirrored)

                # Min head hull is used for the push free
                min_head_hull = hull.getMinkowskiHull(head_and_fans)
                self._node.callDecoration("setConvexHullHead", min_head_hull)
                hull = hull.getMinkowskiHull(Polygon(numpy.array(profile.getSettingValue("machine_head_polygon"),numpy.float32)))
            else:
                self._node.callDecoration("setConvexHullHead", None)
        if self._node.getParent() is None:  # Node was already deleted before job is done.
            self._node.callDecoration("setConvexHullNode",None)
            self._node.callDecoration("setConvexHull", None)
            self._node.callDecoration("setConvexHullJob", None)
            return

        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() and 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)
예제 #9
0
    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]

            # 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)
            duplicates = (vertex_data[:, 0] == vertex_data[:, 1]) | (
                vertex_data[:, 1] == vertex_data[:, 2]) | (
                    vertex_data[:, 0] == vertex_data[:, 2])
            vertex_data = numpy.delete(vertex_data,
                                       numpy.where(duplicates),
                                       axis=0)

            hull = Polygon(vertex_data[:, [0, 2]])

        # 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(
                    [[-0.5, -0.5], [-0.5, 0.5], [0.5, 0.5], [0.5, -0.5]],
                    numpy.float32)))

        profile = Application.getInstance().getMachineManager(
        ).getWorkingProfile()
        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_and_fans = Polygon(
                    numpy.array(
                        profile.getSettingValue(
                            "machine_head_with_fans_polygon"), numpy.float32))

                # Full head hull is used to actually check the order.
                full_head_hull = hull.getMinkowskiHull(head_and_fans)
                self._node.callDecoration("setConvexHullHeadFull",
                                          full_head_hull)
                mirrored = copy.deepcopy(head_and_fans)
                mirrored.mirror([0, 0], [0, 1])  #Mirror horizontally.
                mirrored.mirror([0, 0], [1, 0])  #Mirror vertically.
                head_and_fans = head_and_fans.intersectionConvexHulls(mirrored)

                # Min head hull is used for the push free
                min_head_hull = hull.getMinkowskiHull(head_and_fans)
                self._node.callDecoration("setConvexHullHead", min_head_hull)
                hull = hull.getMinkowskiHull(
                    Polygon(
                        numpy.array(
                            profile.getSettingValue("machine_head_polygon"),
                            numpy.float32)))
            else:
                self._node.callDecoration("setConvexHullHead", None)
        if self._node.getParent(
        ) is None:  # Node was already deleted before job is done.
            self._node.callDecoration("setConvexHullNode", None)
            self._node.callDecoration("setConvexHull", None)
            self._node.callDecoration("setConvexHullJob", None)
            return

        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() and 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)
예제 #10
0
    def _compute2DConvexHull(self) -> Optional[Polygon]:
        if self._node is None:
            return None
        if self._node.callDecoration("isGroup"):
            points = numpy.zeros((0, 2), dtype=numpy.int32)
            for child in self._node.getChildren():
                child_hull = child.callDecoration("_compute2DConvexHull")
                if child_hull:
                    try:
                        points = numpy.append(points, child_hull.getPoints(), axis = 0)
                    except ValueError:
                        pass

                if points.size < 3:
                    return None
            child_polygon = Polygon(points)

            # Check the cache
            if child_polygon == self._2d_convex_hull_group_child_polygon:
                return self._2d_convex_hull_group_result

            convex_hull = child_polygon.getConvexHull() #First calculate the normal convex hull around the points.
            offset_hull = self._offsetHull(convex_hull) #Then apply the offset from the settings.

            # Store the result in the cache
            self._2d_convex_hull_group_child_polygon = child_polygon
            self._2d_convex_hull_group_result = offset_hull

            return offset_hull

        else:
            offset_hull = Polygon([])
            mesh = self._node.getMeshData()
            if mesh is None:
                return Polygon([])  # Node has no mesh data, so just return an empty Polygon.

            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:
                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.
            # Do not throw away vertices: the convex hull may be too small and objects can collide.
            # vertex_data = vertex_data[vertex_data[:,1] >= -0.01]

            if len(vertex_data) >= 4:  # type: ignore # mypy and numpy don't play along well just yet.
                # 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.

                # 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)

                if len(vertex_data) >= 3:
                    convex_hull = hull.getConvexHull()
                    offset_hull = self._offsetHull(convex_hull)

            # Store the result in the cache
            self._2d_convex_hull_mesh = mesh
            self._2d_convex_hull_mesh_world_transform = world_transform
            self._2d_convex_hull_mesh_result = offset_hull

            return offset_hull
예제 #11
0
    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]

            # 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.

            # 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)

        # 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([[-0.5, -0.5], [-0.5, 0.5], [0.5, 0.5], [0.5, -0.5]], numpy.float32)))

        global_stack = Application.getInstance().getGlobalContainerStack()
        if global_stack:
            if global_stack.getProperty("print_sequence", "value")== "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_and_fans = Polygon(numpy.array(global_stack.getProperty("machine_head_with_fans_polygon", "value"), numpy.float32))

                # Full head hull is used to actually check the order.
                full_head_hull = hull.getMinkowskiHull(head_and_fans)
                self._node.callDecoration("setConvexHullHeadFull", full_head_hull)
                mirrored = copy.deepcopy(head_and_fans)
                mirrored.mirror([0, 0], [0, 1]) #Mirror horizontally.
                mirrored.mirror([0, 0], [1, 0]) #Mirror vertically.
                head_and_fans = head_and_fans.intersectionConvexHulls(mirrored)

                # Min head hull is used for the push free
                min_head_hull = hull.getMinkowskiHull(head_and_fans)
                self._node.callDecoration("setConvexHullHead", min_head_hull)
                hull = hull.getMinkowskiHull(Polygon(numpy.array(global_stack.getProperty("machine_head_polygon","value"),numpy.float32)))
            else:
                self._node.callDecoration("setConvexHullHead", None)
        if self._node.getParent() is None:  # Node was already deleted before job is done.
            self._node.callDecoration("setConvexHullNode",None)
            self._node.callDecoration("setConvexHull", None)
            self._node.callDecoration("setConvexHullJob", None)
            return

        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() and 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)