def _split_horizontal(self, section, width, height, depth):
        """We split the section horizontally.

        For an horizontal split the cuboid is placed in the lower
        left corner of the section (section's xyz coordinates), the top
        most side of the cuboid and its horizontal continuation,
        marks the line of division for the split.

        To those we add the cuboid on top of the cuboid we just placed.
        The other two sections created goes all the way to the top of the
        section in which we placed the cuboid.

        +-----------------+
        |                 |
        |                 |
        |                 |
        |                 |
        +-------+---------+
        |#######|         |
        |#######|         |
        |#######|         |
        +-------+---------+

        If the cuboid width is equal to the the section width, only two
        sections are created over the cuboid and on top of it. If the cuboid
        height is equal to the section height, only two sections to the right
        and the top of the cuboid is created. If both width and height are
        equal, only one section is created on top of the cuboid. If both width,
        height and depth are equal, no sections are created.
        """

        # First remove the section we are splitting so it doesn't
        # interfere when later we try to merge the resulting split
        # cuboids, with the rest of free sections.
        # self._sections.remove(section)

        # Creates three new empty sections, and returns the new cuboid.
        if height < section.height:
            self._add_section(
                Cuboid(section.x, section.y + height, section.z, section.width,
                       section.height - height, section.depth))

        if width < section.width:
            self._add_section(
                Cuboid(section.x + width, section.y, section.z,
                       section.width - width, height, section.depth))

        if depth < section.depth:
            self._add_section(
                Cuboid(section.x, section.y, section.z + depth, width, height,
                       section.depth - depth))
    def _split_vertical(self, section, width, height, depth):
        """We split the section vertically.

        For a vertical split the cuboid is placed in the lower
        left corner of the section (section's xyz coordinates), the
        right most side of the cuboid and its vertical continuation,
        marks the line of division for the split.

        To those we add the cuboid on top of the cuboid we just placed.
        The other two sections created goes all the way to the top of the
        section in which we placed the cuboid.

        +-------+---------+
        |       |         |
        |       |         |
        |       |         |
        |       |         |
        +-------+         |
        |#######|         |
        |#######|         |
        |#######|         |
        +-------+---------+

        If the cuboid width is equal to the the section width, only two
        sections are created over the cuboid and on top of it. If the cuboid
        height is equal to the section height, only two sections to the right
        and the top of the cuboid is created. If both width and height are
        equal, only one section is created on top of the cuboid. If both width,
        height and depth are equal, no sections are created.
        """

        # When a section is split, depending on the cuboid size
        # three, two, one, or no new sections will be created.

        if height < section.height:
            self._add_section(
                Cuboid(section.x, section.y + height, section.z, width,
                       section.height - height, section.depth))

        if width < section.width:
            self._add_section(
                Cuboid(section.x + width, section.y, section.z,
                       section.width - width, section.height, section.depth))

        if depth < section.depth:
            self._add_section(
                Cuboid(section.x, section.y, section.z + depth, width, height,
                       section.depth - depth))
    def _select_position(self, w, h, d):
        """Find max_cub with best fitness for placing a cuboid(w*h*d)

        Arguments:
            w (int, float): Cuboid width
            h (int, float): Cuboid height
            d (int, float): Cuboid depth

        Returns:
            (cub, max_cub)
            cub (Cuboid): Placed Cuboid or None if was unable.
            max_cub (Cuboid): Maximal cuboid were cub was placed
        """
        if not self._max_cubs:
            return None, None

        # Normal cuboid
        fitn = ((self._cub_fitness(m, w, h, d), w, h, d, m) for m in
                self._max_cubs if self._cub_fitness(m, w, h, d) is not None)

        # Rotated cuboid
        fitr = ((self._cub_fitness(m, h, w, d), h, w, d, m) for m in
                self._max_cubs if self._cub_fitness(m, h, w, d) is not None)

        if not self.rot:
            fitr = []

        fit = itertools.chain(fitn, fitr)

        try:
            _, w, h, d, m = min(fit, key=first_item)
        except ValueError:
            return None, None

        return Cuboid(m.x, m.y, m.z, w, h, d), m
    def add_cub(self, width, height, depth, rid=None):
        """Add cuboid of widthxheightxdepth dimensions.

        Arguments:
            width (int, float): Cuboid width
            height (int, float): Cuboid height
            depth (int, float): Cuboid depth
            rid: Optional cuboid user id

        Returns:
            Cuboid: Cuboid with placement coordinates
            None: If the cuboid couldn't be placed.
        """
        assert (width > 0 and height > 0 and depth > 0)

        # Obtain the best section to place the cuboid.
        section, rotated = self._select_fittest_section(width, height, depth)
        if not section:
            return None

        if rotated:
            # This should be changed, I'm just supposing that item should be
            # oriented upward all the time.
            # See : pack_algo.py:49
            width, height = height, width

        # Remove section, split and store results
        self._sections.remove(section)
        self._split(section, width, height, depth)

        # Store Cuboid in the selected position
        cub = Cuboid(section.x, section.y, section.z, width, height, depth,
                     rid)
        self.cuboids.append(cub)
        return cub
    def validate_packing(self):
        """Check for collisions between cuboids.

        Also check all are placed inside surface.
        """
        volume = Cuboid(0, 0, 0, self.width, self.height, self.width)

        for c in self:
            if not volume.contains(c):
                raise Exception("Cuboid placed outside volume.")

        cuboids = [c for c in self]
        if len(cuboids) <= 1:
            return

        for c1 in range(0, len(cuboids)-2):
            for c2 in range(c1+1, len(cuboids)-1):
                if cuboids[c1].intersects(cuboids[c2]):
                    raise Exception("Cuboid collision detected")
    def _generate_splits(self, m, c):
        """Get new cuboids splits after cuboid is placed

        When a cuboid is placed inside a maximal cuboid, it stops being one
        and up to 5 new maximal cuboids may appear depending on the
        placement.
        _generate_splits calculates them.

        Arguments:
            m (Cuboid): max_cub Cuboid
            r (Cuboid): Cuboid placed

        Returns:
            list : list containing new maximal cuboids or an empty list
        """
        new_cubs = []

        if c.left > m.left:
            new_cubs.append(Cuboid(
                m.left, m.bottom, m.outeye,
                c.left - m.left, m.height, m.depth))
        if c.right < m.right:
            new_cubs.append(Cuboid(
                c.right, m.bottom, m.outeye,
                m.right - c.right, m.height, m.depth))
        if c.top < m.top:
            new_cubs.append(Cuboid(
                m.left, c.top, m.outeye,
                m.width, m.top - c.top, m.depth))
        if c.bottom > m.bottom:
            new_cubs.append(Cuboid(
                m.left, m.bottom, m.outeye,
                m.width, c.bottom - m.bottom, m.depth))
        if c.ineye < m.ineye:
            new_cubs.append(Cuboid(
                c.left, c.bottom, c.ineye,
                c.width, c.height, m.ineye - c.ineye))

        return new_cubs
    def __init__(self, width, height, depth, rot=True, *args, **kwargs):
        """Initialize packing algorithm

        Arguments:
            width (int, float): Packing volume width
            height (int, float): Packing volume height
            depth (int, float): Packing volume depth
            rot (bool): Cuboid rotation enabled or disabled
        """
        self.width = width
        self.height = height
        self.depth = depth
        self.rot = rot
        self.cuboids = []
        self._surface = Cuboid(0, 0, 0, width, height, depth)
        self.reset()
    def _select_position(self, w, h, d):
        """Find lowest position

        Select the position where the y coordinate of the top of the cuboid
        is lower, if there are severtal pick the one with the smallest x
        coordinate
        """
        fitn = ((m.y + h, m.x, m.z, w, h, d, m) for m in self._max_cubs
                if self._cub_fitness(m, w, h, d) is not None)
        fitr = ((m.y + w, m.x, m.z, h, w, d, m) for m in self._max_cubs
                if self._cub_fitness(m, h, w, d) is not None)

        if not self.rot:
            fitr = []

        fit = itertools.chain(fitn, fitr)

        try:
            _, _, _, w, h, d, m = min(fit, key=first_item)
        except ValueError:
            return None, None

        return Cuboid(m.x, m.y, m.z, w, h, d), m
 def reset(self):
     super(MaxCubs, self).reset()
     self._max_cubs = [Cuboid(0, 0, 0, self.width, self.height, self.depth)]
Esempio n. 10
0
 def add_waste(self, x, y, z, width, height, depth):
     """Add new waste section"""
     self._add_section(Cuboid(x, y, z, width, height, depth))
 def reset(self):
     super(Guillotine, self).reset()
     self._sections = []
     self._add_section(Cuboid(0, 0, 0, self.width, self.height, self.depth))