def _onChangeTimerFinished(self):
        if not self._enabled:
            return

        root = self._controller.getScene().getRoot()
        for node in BreadthFirstIterator(root):
            if node is root or type(node) is not SceneNode:
                continue

            bbox = node.getBoundingBox()
            if not bbox or not bbox.isValid():
                self._change_timer.start()
                continue

            build_volume_bounding_box = copy.deepcopy(
                self._build_volume.getBoundingBox())
            build_volume_bounding_box.setBottom(
                -9001)  # Ignore intersections with the bottom
            node._outside_buildarea = False

            # Mark the node as outside the build volume if the bounding box test fails.
            if build_volume_bounding_box.intersectsBox(
                    bbox
            ) != AxisAlignedBox.IntersectionResult.FullIntersection:
                node._outside_buildarea = True

            # Move it downwards if bottom is above platform
            move_vector = Vector()
            if not (node.getParent()
                    and node.getParent().callDecoration("isGroup")
                    ):  #If an object is grouped, don't move it down
                z_offset = node.callDecoration(
                    "getZOffset") if node.getDecorator(
                        ZOffsetDecorator.ZOffsetDecorator) else 0
                if bbox.bottom > 0:
                    move_vector.setY(-bbox.bottom + z_offset)
                elif bbox.bottom < z_offset:
                    move_vector.setY((-bbox.bottom) - z_offset)

            #if not Float.fuzzyCompare(bbox.bottom, 0.0):
            #   pass#move_vector.setY(-bbox.bottom)

            # If there is no convex hull for the node, start calculating it and continue.
            if not node.getDecorator(ConvexHullDecorator):
                node.addDecorator(ConvexHullDecorator())

            if not node.callDecoration("getConvexHull"):
                if not node.callDecoration("getConvexHullJob"):
                    job = ConvexHullJob.ConvexHullJob(node)
                    job.start()
                    node.callDecoration("setConvexHullJob", job)

            elif Preferences.getInstance().getValue(
                    "physics/automatic_push_free"):
                # Check for collisions between convex hulls
                for other_node in BreadthFirstIterator(root):
                    # Ignore root, ourselves and anything that is not a normal SceneNode.
                    if other_node is root or type(
                            other_node) is not SceneNode or other_node is node:
                        continue

                    # Ignore colissions of a group with it's own children
                    if other_node in node.getAllChildren(
                    ) or node in other_node.getAllChildren():
                        continue

                    # Ignore colissions within a group
                    if other_node.getParent().callDecoration(
                            "isGroup") is not None or node.getParent(
                            ).callDecoration("isGroup") is not None:
                        continue
                        #if node.getParent().callDecoration("isGroup") is other_node.getParent().callDecoration("isGroup"):
                        #    continue

                    # Ignore nodes that do not have the right properties set.
                    if not other_node.callDecoration(
                            "getConvexHull") or not other_node.getBoundingBox(
                            ):
                        continue

                    # Check to see if the bounding boxes intersect. If not, we can ignore the node as there is no way the hull intersects.
                    #if node.getBoundingBox().intersectsBox(other_node.getBoundingBox()) == AxisAlignedBox.IntersectionResult.NoIntersection:
                    #    continue

                    # Get the overlap distance for both convex hulls. If this returns None, there is no intersection.
                    try:
                        head_hull = node.callDecoration("getConvexHullHead")
                        if head_hull:
                            overlap = head_hull.intersectsPolygon(
                                other_node.callDecoration("getConvexHullHead"))
                            if not overlap:
                                other_head_hull = other_node.callDecoration(
                                    "getConvexHullHead")
                                if other_head_hull:
                                    overlap = node.callDecoration(
                                        "getConvexHullHead").intersectsPolygon(
                                            other_head_hull)
                        else:
                            overlap = node.callDecoration(
                                "getConvexHull").intersectsPolygon(
                                    other_node.callDecoration("getConvexHull"))
                    except:
                        overlap = None  #It can sometimes occur that the caclulated convex hull has no size, in which case there is no overlap.

                    if overlap is None:
                        continue
                    move_vector.setX(overlap[0] * 1.1)
                    move_vector.setZ(overlap[1] * 1.1)
            convex_hull = node.callDecoration("getConvexHull")
            if convex_hull:
                if not convex_hull.isValid():
                    return
                # Check for collisions between disallowed areas and the object
                for area in self._build_volume.getDisallowedAreas():
                    overlap = convex_hull.intersectsPolygon(area)
                    if overlap is None:
                        continue

                    node._outside_buildarea = True

            if move_vector != Vector():
                op = PlatformPhysicsOperation.PlatformPhysicsOperation(
                    node, move_vector)
                op.push()
Пример #2
0
    def _onChangeTimerFinished(self):
        if not self._enabled:
            return

        root = self._controller.getScene().getRoot()

        # Keep a list of nodes that are moving. We use this so that we don't move two intersecting objects in the
        # same direction.
        transformed_nodes = []

        group_nodes = []
        # We try to shuffle all the nodes to prevent "locked" situations, where iteration B inverts iteration A.
        # By shuffling the order of the nodes, this might happen a few times, but at some point it will resolve.
        nodes = list(BreadthFirstIterator(root))
        random.shuffle(nodes)
        for node in nodes:
            if node is root or type(
                    node) is not SceneNode or node.getBoundingBox() is None:
                continue

            bbox = node.getBoundingBox()

            # Ignore intersections with the bottom
            build_volume_bounding_box = self._build_volume.getBoundingBox()
            if build_volume_bounding_box:
                # It's over 9000!
                build_volume_bounding_box = build_volume_bounding_box.set(
                    bottom=-9001)
            else:
                # No bounding box. This is triggered when running Cura from command line with a model for the first time
                # In that situation there is a model, but no machine (and therefore no build volume.
                return
            node._outside_buildarea = False

            # Mark the node as outside the build volume if the bounding box test fails.
            if build_volume_bounding_box.intersectsBox(
                    bbox
            ) != AxisAlignedBox.IntersectionResult.FullIntersection:
                node._outside_buildarea = True

            if node.callDecoration("isGroup"):
                group_nodes.append(node)  # Keep list of affected group_nodes

            # Move it downwards if bottom is above platform
            move_vector = Vector()
            if Preferences.getInstance().getValue(
                    "physics/automatic_drop_down") and not (
                        node.getParent() and node.getParent().callDecoration(
                            "isGroup")) and node.isEnabled(
                            ):  #If an object is grouped, don't move it down
                z_offset = node.callDecoration(
                    "getZOffset") if node.getDecorator(
                        ZOffsetDecorator.ZOffsetDecorator) else 0
                move_vector = move_vector.set(y=-bbox.bottom + z_offset)

            # If there is no convex hull for the node, start calculating it and continue.
            if not node.getDecorator(ConvexHullDecorator):
                node.addDecorator(ConvexHullDecorator())

            if Preferences.getInstance().getValue(
                    "physics/automatic_push_free"):
                # Check for collisions between convex hulls
                for other_node in BreadthFirstIterator(root):
                    # Ignore root, ourselves and anything that is not a normal SceneNode.
                    if other_node is root or type(
                            other_node) is not SceneNode or other_node is node:
                        continue

                    # Ignore collisions of a group with it's own children
                    if other_node in node.getAllChildren(
                    ) or node in other_node.getAllChildren():
                        continue

                    # Ignore collisions within a group
                    if other_node.getParent() and node.getParent() and (
                            other_node.getParent().callDecoration("isGroup")
                            is not None
                            or node.getParent().callDecoration("isGroup")
                            is not None):
                        continue

                    # Ignore nodes that do not have the right properties set.
                    if not other_node.callDecoration(
                            "getConvexHull") or not other_node.getBoundingBox(
                            ):
                        continue

                    if other_node in transformed_nodes:
                        continue  # Other node is already moving, wait for next pass.

                    overlap = (0, 0)  # Start loop with no overlap
                    current_overlap_checks = 0
                    # Continue to check the overlap until we no longer find one.
                    while overlap and current_overlap_checks < self._max_overlap_checks:
                        current_overlap_checks += 1
                        head_hull = node.callDecoration("getConvexHullHead")
                        if head_hull:  # One at a time intersection.
                            overlap = head_hull.translate(
                                move_vector.x,
                                move_vector.z).intersectsPolygon(
                                    other_node.callDecoration("getConvexHull"))
                            if not overlap:
                                other_head_hull = other_node.callDecoration(
                                    "getConvexHullHead")
                                if other_head_hull:
                                    overlap = node.callDecoration(
                                        "getConvexHull").translate(
                                            move_vector.x,
                                            move_vector.z).intersectsPolygon(
                                                other_head_hull)
                                    if overlap:
                                        # Moving ensured that overlap was still there. Try anew!
                                        move_vector = move_vector.set(
                                            x=move_vector.x +
                                            overlap[0] * self._move_factor,
                                            z=move_vector.z +
                                            overlap[1] * self._move_factor)
                            else:
                                # Moving ensured that overlap was still there. Try anew!
                                move_vector = move_vector.set(
                                    x=move_vector.x +
                                    overlap[0] * self._move_factor,
                                    z=move_vector.z +
                                    overlap[1] * self._move_factor)
                        else:
                            own_convex_hull = node.callDecoration(
                                "getConvexHull")
                            other_convex_hull = other_node.callDecoration(
                                "getConvexHull")
                            if own_convex_hull and other_convex_hull:
                                overlap = own_convex_hull.translate(
                                    move_vector.x,
                                    move_vector.z).intersectsPolygon(
                                        other_convex_hull)
                                if overlap:  # Moving ensured that overlap was still there. Try anew!
                                    move_vector = move_vector.set(
                                        x=move_vector.x +
                                        overlap[0] * self._move_factor,
                                        z=move_vector.z +
                                        overlap[1] * self._move_factor)
                            else:
                                # This can happen in some cases if the object is not yet done with being loaded.
                                #  Simply waiting for the next tick seems to resolve this correctly.
                                overlap = None

            convex_hull = node.callDecoration("getConvexHull")
            if convex_hull:
                if not convex_hull.isValid():
                    return
                # Check for collisions between disallowed areas and the object
                for area in self._build_volume.getDisallowedAreas():
                    overlap = convex_hull.intersectsPolygon(area)
                    if overlap is None:
                        continue
                    node._outside_buildarea = True

            if not Vector.Null.equals(move_vector, epsilon=1e-5):
                transformed_nodes.append(node)
                op = PlatformPhysicsOperation.PlatformPhysicsOperation(
                    node, move_vector)
                op.push()

        # Group nodes should override the _outside_buildarea property of their children.
        for group_node in group_nodes:
            for child_node in group_node.getAllChildren():
                child_node._outside_buildarea = group_node._outside_buildarea
    def _onChangeTimerFinished(self, was_triggered_by_tool=False):
        if not self._enabled:
            return

        root = self._controller.getScene().getRoot()

        # Keep a list of nodes that are moving. We use this so that we don't move two intersecting objects in the
        # same direction.
        transformed_nodes = []

        # We try to shuffle all the nodes to prevent "locked" situations, where iteration B inverts iteration A.
        # By shuffling the order of the nodes, this might happen a few times, but at some point it will resolve.
        nodes = list(BreadthFirstIterator(root))

        # Only check nodes inside build area.
        nodes = [
            node for node in nodes if (hasattr(node, "_outside_buildarea")
                                       and not node._outside_buildarea)
        ]

        random.shuffle(nodes)
        for node in nodes:
            if node is root or type(
                    node) is not SceneNode or node.getBoundingBox() is None:
                continue

            bbox = node.getBoundingBox()

            # Move it downwards if bottom is above platform
            move_vector = Vector()

            if Preferences.getInstance().getValue(
                    "physics/automatic_drop_down") and not (
                        node.getParent() and node.getParent().callDecoration(
                            "isGroup")) and node.isEnabled(
                            ):  #If an object is grouped, don't move it down
                z_offset = node.callDecoration(
                    "getZOffset") if node.getDecorator(
                        ZOffsetDecorator.ZOffsetDecorator) else 0
                move_vector = move_vector.set(y=-bbox.bottom + z_offset)

            # If there is no convex hull for the node, start calculating it and continue.
            if not node.getDecorator(ConvexHullDecorator):
                node.addDecorator(ConvexHullDecorator())

            if Preferences.getInstance().getValue(
                    "physics/automatic_push_free"):
                # Check for collisions between convex hulls
                for other_node in BreadthFirstIterator(root):
                    # Ignore root, ourselves and anything that is not a normal SceneNode.
                    if other_node is root or type(
                            other_node) is not SceneNode or other_node is node:
                        continue

                    # Ignore collisions of a group with it's own children
                    if other_node in node.getAllChildren(
                    ) or node in other_node.getAllChildren():
                        continue

                    # Ignore collisions within a group
                    if other_node.getParent() and node.getParent() and (
                            other_node.getParent().callDecoration("isGroup")
                            is not None
                            or node.getParent().callDecoration("isGroup")
                            is not None):
                        continue

                    # Ignore nodes that do not have the right properties set.
                    if not other_node.callDecoration(
                            "getConvexHull") or not other_node.getBoundingBox(
                            ):
                        continue

                    if other_node in transformed_nodes:
                        continue  # Other node is already moving, wait for next pass.

                    overlap = (0, 0)  # Start loop with no overlap
                    current_overlap_checks = 0
                    # Continue to check the overlap until we no longer find one.
                    while overlap and current_overlap_checks < self._max_overlap_checks:
                        current_overlap_checks += 1
                        head_hull = node.callDecoration("getConvexHullHead")
                        if head_hull:  # One at a time intersection.
                            overlap = head_hull.translate(
                                move_vector.x,
                                move_vector.z).intersectsPolygon(
                                    other_node.callDecoration("getConvexHull"))
                            if not overlap:
                                other_head_hull = other_node.callDecoration(
                                    "getConvexHullHead")
                                if other_head_hull:
                                    overlap = node.callDecoration(
                                        "getConvexHull").translate(
                                            move_vector.x,
                                            move_vector.z).intersectsPolygon(
                                                other_head_hull)
                                    if overlap:
                                        # Moving ensured that overlap was still there. Try anew!
                                        move_vector = move_vector.set(
                                            x=move_vector.x +
                                            overlap[0] * self._move_factor,
                                            z=move_vector.z +
                                            overlap[1] * self._move_factor)
                            else:
                                # Moving ensured that overlap was still there. Try anew!
                                move_vector = move_vector.set(
                                    x=move_vector.x +
                                    overlap[0] * self._move_factor,
                                    z=move_vector.z +
                                    overlap[1] * self._move_factor)
                        else:
                            own_convex_hull = node.callDecoration(
                                "getConvexHull")
                            other_convex_hull = other_node.callDecoration(
                                "getConvexHull")
                            if own_convex_hull and other_convex_hull:
                                overlap = own_convex_hull.translate(
                                    move_vector.x,
                                    move_vector.z).intersectsPolygon(
                                        other_convex_hull)
                                if overlap:  # Moving ensured that overlap was still there. Try anew!
                                    move_vector = move_vector.set(
                                        x=move_vector.x +
                                        overlap[0] * self._move_factor,
                                        z=move_vector.z +
                                        overlap[1] * self._move_factor)
                            else:
                                # This can happen in some cases if the object is not yet done with being loaded.
                                #  Simply waiting for the next tick seems to resolve this correctly.
                                overlap = None

            if not Vector.Null.equals(move_vector, epsilon=1e-5):
                transformed_nodes.append(node)
                op = PlatformPhysicsOperation.PlatformPhysicsOperation(
                    node, move_vector)
                op.push()

        # After moving, we have to evaluate the boundary checks for nodes
        build_volume = Application.getInstance().getBuildVolume()
        build_volume.updateNodeBoundaryCheck()
Пример #4
0
    def _onChangeTimerFinished(self):
        if not self._enabled:
            return

        root = self._controller.getScene().getRoot()

        # Keep a list of nodes that are moving. We use this so that we don't move two intersecting objects in the
        # same direction.
        transformed_nodes = []

        for node in BreadthFirstIterator(root):
            if node is root or type(
                    node) is not SceneNode or node.getBoundingBox() is None:
                continue

            bbox = node.getBoundingBox()

            # Ignore intersections with the bottom
            build_volume_bounding_box = self._build_volume.getBoundingBox()
            if build_volume_bounding_box:
                # It's over 9000!
                build_volume_bounding_box = build_volume_bounding_box.set(
                    bottom=-9001)
            else:
                # No bounding box. This is triggered when running Cura from command line with a model for the first time
                # In that situation there is a model, but no machine (and therefore no build volume.
                return
            node._outside_buildarea = False

            # Mark the node as outside the build volume if the bounding box test fails.
            if build_volume_bounding_box.intersectsBox(
                    bbox
            ) != AxisAlignedBox.IntersectionResult.FullIntersection:
                node._outside_buildarea = True

            # Move it downwards if bottom is above platform
            move_vector = Vector()
            if Preferences.getInstance().getValue(
                    "physics/automatic_drop_down") and not (
                        node.getParent()
                        and node.getParent().callDecoration("isGroup")
                    ):  #If an object is grouped, don't move it down
                z_offset = node.callDecoration(
                    "getZOffset") if node.getDecorator(
                        ZOffsetDecorator.ZOffsetDecorator) else 0
                move_vector = move_vector.set(y=-bbox.bottom + z_offset)

            # If there is no convex hull for the node, start calculating it and continue.
            if not node.getDecorator(ConvexHullDecorator):
                node.addDecorator(ConvexHullDecorator())

            if Preferences.getInstance().getValue(
                    "physics/automatic_push_free"):
                # Check for collisions between convex hulls
                for other_node in BreadthFirstIterator(root):
                    # Ignore root, ourselves and anything that is not a normal SceneNode.
                    if other_node is root or type(
                            other_node) is not SceneNode or other_node is node:
                        continue

                    # Ignore collisions of a group with it's own children
                    if other_node in node.getAllChildren(
                    ) or node in other_node.getAllChildren():
                        continue

                    # Ignore collisions within a group
                    if other_node.getParent().callDecoration(
                            "isGroup") is not None or node.getParent(
                            ).callDecoration("isGroup") is not None:
                        continue

                    # Ignore nodes that do not have the right properties set.
                    if not other_node.callDecoration(
                            "getConvexHull") or not other_node.getBoundingBox(
                            ):
                        continue

                    if other_node in transformed_nodes:
                        continue  # Other node is already moving, wait for next pass.

                    # Get the overlap distance for both convex hulls. If this returns None, there is no intersection.
                    head_hull = node.callDecoration("getConvexHullHead")
                    if head_hull:
                        overlap = head_hull.intersectsPolygon(
                            other_node.callDecoration("getConvexHullHead"))
                        if not overlap:
                            other_head_hull = other_node.callDecoration(
                                "getConvexHullHead")
                            if other_head_hull:
                                overlap = node.callDecoration(
                                    "getConvexHullHead").intersectsPolygon(
                                        other_head_hull)
                    else:
                        own_convex_hull = node.callDecoration("getConvexHull")
                        other_convex_hull = other_node.callDecoration(
                            "getConvexHull")
                        if own_convex_hull and other_convex_hull:
                            overlap = own_convex_hull.intersectsPolygon(
                                other_convex_hull)
                        else:
                            # This can happen in some cases if the object is not yet done with being loaded.
                            #  Simply waiting for the next tick seems to resolve this correctly.
                            overlap = None

                    if overlap is None:
                        continue
                    move_vector = move_vector.set(x=overlap[0] * 1.1,
                                                  z=overlap[1] * 1.1)
            convex_hull = node.callDecoration("getConvexHull")
            if convex_hull:
                if not convex_hull.isValid():
                    return
                # Check for collisions between disallowed areas and the object
                for area in self._build_volume.getDisallowedAreas():
                    overlap = convex_hull.intersectsPolygon(area)
                    if overlap is None:
                        continue

                    node._outside_buildarea = True

            if not Vector.Null.equals(move_vector, epsilon=1e-5):
                transformed_nodes.append(node)
                op = PlatformPhysicsOperation.PlatformPhysicsOperation(
                    node, move_vector)
                op.push()