Пример #1
0
    def rotationTo(v1, v2):
        d = v1.dot(v2)

        if d >= 1.0:
            return Quaternion() # Vectors are equal, no rotation needed.

        q = None
        if Float.fuzzyCompare(d, -1.0, 1e-6):
            axis = Vector.Unit_X.cross(v1)

            if Float.fuzzyCompare(axis.length(), 0.0):
                axis = Vector.Unit_Y.cross(v1)

            axis.normalize()
            q = Quaternion()
            q.setByAngleAxis(math.pi, axis)
        else:
            s = math.sqrt((1.0 + d) * 2.0)
            invs = 1.0 / s

            c = v1.cross(v2)

            q = Quaternion(
                c.x * invs,
                c.y * invs,
                c.z * invs,
                s * 0.5
            )
            q.normalize()

        return q
Пример #2
0
    def slerp(start, end, amount):
        if Float.fuzzyCompare(amount, 0.0):
            return start
        elif Float.fuzzyCompare(amount, 1.0):
            return end

        rho = math.acos(start.dot(end))
        return (start * math.sin((1 - amount) * rho) + end * math.sin(amount * rho)) / math.sin(rho)
Пример #3
0
    def test_setByAxis(self):
        q = Quaternion()

        q.setByAngleAxis(math.pi / 2, Vector.Unit_Z)

        self.assertEqual(q.x, 0.0)
        self.assertEqual(q.y, 0.0)
        self.assertTrue(Float.fuzzyCompare(q.z, math.sqrt(2.0) / 2.0, 1e-6))
        self.assertTrue(Float.fuzzyCompare(q.w, math.sqrt(2.0) / 2.0, 1e-6))
Пример #4
0
    def test_rotateVector(self):
        q1 = Quaternion()
        q1.setByAngleAxis(math.pi / 2, Vector.Unit_Z)

        v = Vector(0, 1, 0)
        v = q1.rotate(v)

        self.assertTrue(Float.fuzzyCompare(v.x, -1.0, 1e-6))
        self.assertTrue(Float.fuzzyCompare(v.y, 0.0, 1e-6))
        self.assertTrue(Float.fuzzyCompare(v.z, 0.0, 1e-6))
Пример #5
0
    def test_fromMatrix(self):
        m = Matrix()
        m.setByRotationAxis(math.pi / 2, Vector.Unit_Z)

        q1 = Quaternion.fromMatrix(m)

        q2 = Quaternion()
        q2.setByAngleAxis(math.pi / 2, Vector.Unit_Z)

        self.assertTrue(Float.fuzzyCompare(q1.x, q2.x, 1e-6))
        self.assertTrue(Float.fuzzyCompare(q1.y, q2.y, 1e-6))
        self.assertTrue(Float.fuzzyCompare(q1.z, q2.z, 1e-6))
        self.assertTrue(Float.fuzzyCompare(q1.w, q2.w, 1e-6))
Пример #6
0
    def _onChangeTimerFinished(self):
        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():
                continue

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

            # Move the node upwards if the bottom is below the build platform.
            move_vector = Vector()
            if not Float.fuzzyCompare(bbox.bottom, 0.0):
                move_vector.setY(-bbox.bottom)

            # If there is no convex hull for the node, start calculating it and continue.
            if not hasattr(node, "_convex_hull"):
                if not hasattr(node, "_convex_hull_job"):
                    job = ConvexHullJob.ConvexHullJob(node)
                    job.start()
                    node._convex_hull_job = job
            elif Selection.isSelected(node):
                pass
            else:
                # 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 nodes that do not have the right properties set.
                    if not hasattr(other_node, "_convex_hull") 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.
                    overlap = node._convex_hull.intersectsPolygon(other_node._convex_hull)
                    if overlap is None:
                        continue

                    move_vector.setX(overlap[0] * 1.1)
                    move_vector.setZ(overlap[1] * 1.1)

            if move_vector != Vector():
                op = PlatformPhysicsOperation.PlatformPhysicsOperation(node, move_vector)
                op.push()

            if node.getBoundingBox().intersectsBox(self._build_volume.getBoundingBox()) == AxisAlignedBox.IntersectionResult.FullIntersection:
                op = ScaleToBoundsOperation(node, self._build_volume.getBoundingBox())
                op.push()
Пример #7
0
 def test_mirror(self, data):
     polygon = Polygon(numpy.array(data["points"], numpy.float32)) #Create a polygon with the specified points.
     polygon.mirror(data["axis_point"], data["axis_direction"]) #Mirror over the specified axis.
     points = polygon.getPoints()
     assert len(points) == len(data["points"]) #Must have the same amount of vertices.
     for point_index in range(len(points)):
         assert len(points[point_index]) == len(data["answer"][point_index]) #Same dimensionality (2).
         for dimension in range(len(points[point_index])):
             assert Float.fuzzyCompare(points[point_index][dimension], data["answer"][point_index][dimension]) #All points must be equal.
Пример #8
0
    def test_project(self):
        p = Polygon(numpy.array([
            [0.0, 1.0],
            [1.0, 1.0],
            [1.0, 2.0],
            [0.0, 2.0]
        ], numpy.float32))

        normal = numpy.array([0.0, 1.0])
        self.assertEqual((1.0, 2.0), p.project(normal))

        normal = numpy.array([1.0, 0.0])
        self.assertEqual((0.0, 1.0), p.project(normal))

        normal = numpy.array([math.sqrt(0.5), math.sqrt(0.5)])
        result = p.project(normal)
        self.assertTrue(Float.fuzzyCompare(result[0], 0.70710678), "{0} does not equal {1}".format(result[0], 0.70710678))
        self.assertTrue(Float.fuzzyCompare(result[1], 2.12132034), "{0} does not equal {1}".format(result[1], 2.12132034))
Пример #9
0
 def test_project(self, data):
     p = Polygon(numpy.array([
         [0.0, 1.0],
         [1.0, 1.0],
         [1.0, 2.0],
         [0.0, 2.0]
     ], numpy.float32))
     result = p.project(data["normal"]) #Project the polygon onto the specified normal vector.
     assert len(result) == len(data["answer"]) #Same dimensionality (2).
     for dimension in range(len(result)):
         assert Float.fuzzyCompare(result[dimension], data["answer"][dimension])
Пример #10
0
 def setObjectWidth(self, width):
     obj = Selection.getSelectedObject(0)
     if obj:
         width = float(width)
         obj_width = obj.getBoundingBox().width
         if not Float.fuzzyCompare(obj_width, width, DIMENSION_TOLERANCE):
             scale_factor = width / obj_width
             if self._non_uniform_scale:
                 scale_vector = Vector(scale_factor, 1, 1)
             else:
                 scale_vector = Vector(scale_factor, scale_factor, scale_factor)
             Selection.applyOperation(ScaleOperation, scale_vector, scale_around_point = obj.getWorldPosition())
Пример #11
0
 def setObjectHeight(self, height):
     obj = Selection.getSelectedObject(0)
     if obj:
         height = float(height)
         obj_height = obj.getBoundingBox().height
         if not Float.fuzzyCompare(obj_height, height, DIMENSION_TOLERANCE):
             scale_factor = height / obj_height
             if self._non_uniform_scale:
                 scale_vector = Vector(1, scale_factor, 1)
             else:
                 scale_vector = Vector(scale_factor, scale_factor, scale_factor)
             Selection.applyOperation(ScaleOperation, scale_vector)
Пример #12
0
 def setObjectDepth(self, depth):
     obj = Selection.getSelectedObject(0)
     if obj:
         depth = float(depth)
         obj_depth = obj.getBoundingBox().depth
         if not Float.fuzzyCompare(obj_depth, depth, DIMENSION_TOLERANCE):
             scale_factor = depth / obj_depth
             if self._non_uniform_scale:
                 scale_vector = Vector(1, 1, scale_factor)
             else:
                 scale_vector = Vector(scale_factor, scale_factor, scale_factor)
             Selection.applyOperation(ScaleOperation, scale_vector)
Пример #13
0
    def setObjectWidth(self, width):
        obj = Selection.getSelectedObject(0)
        if obj:
            width = float(width)
            obj_width = obj.getBoundingBox().width
            if not Float.fuzzyCompare(obj_width, width, DIMENSION_TOLERANCE):
                scale_factor = width / obj_width
                if self._non_uniform_scale:
                    scale_vector = Vector(scale_factor, 1, 1)
                else:
                    scale_vector = Vector(scale_factor, scale_factor, scale_factor)

                self._scaleSelectedNodes(scale_vector)
Пример #14
0
    def setX(self, x):
        parsed_x = self._parseInt(x)
        bounding_box = Selection.getBoundingBox()

        op = GroupedOperation()
        if not Float.fuzzyCompare(parsed_x, float(bounding_box.center.x), DIMENSION_TOLERANCE):
            for selected_node in Selection.getAllSelectedObjects():
                world_position = selected_node.getWorldPosition()
                new_position = world_position.set(x=parsed_x + (world_position.x - bounding_box.center.x))
                node_op = TranslateOperation(selected_node, new_position, set_position = True)
                op.addOperation(node_op)
            op.push()
        self._controller.toolOperationStopped.emit(self)
Пример #15
0
    def intersectsRay(self, ray):
        w = ray.origin - (self._normal * self._distance)

        nDotR = self._normal.dot(ray.direction)
        nDotW = -self._normal.dot(w)

        if Float.fuzzyCompare(nDotR, 0.0):
            return False

        t = nDotW / nDotR
        if t < 0:
            return False

        return t
Пример #16
0
    def setZ(self, z):
        parsed_z = self._parseInt(z)
        bounding_box = Selection.getBoundingBox()

        op = GroupedOperation()
        if not Float.fuzzyCompare(parsed_z, float(bounding_box.center.y), DIMENSION_TOLERANCE):
            for selected_node in Selection.getAllSelectedObjects():
                # Note: The switching of z & y is intentional. We display z as up for the user,
                # But store the data in openGL space.
                world_position = selected_node.getWorldPosition()
                new_position = world_position.set(y=parsed_z + (world_position.y - bounding_box.bottom))
                node_op = TranslateOperation(selected_node, new_position, set_position = True)
                op.addOperation(node_op)
            op.push()
        self._controller.toolOperationStopped.emit(self)
Пример #17
0
 def test_intersectConvexHull(self, data):
     p1 = Polygon(numpy.array(data["p1"]))
     p2 = Polygon(numpy.array(data["p2"]))
     result = p1.intersectionConvexHulls(p2)
     assert len(result.getPoints()) == len(data["answer"]) #Same amount of vertices.
     isCorrect = False
     for rotation in range(0, len(result.getPoints())): #The order of vertices doesn't matter, so rotate the result around and if any check succeeds, the answer is correct.
         thisCorrect = True #Is this rotation correct?
         for vertex in range(0, len(result.getPoints())):
             for dimension in range(0, len(result.getPoints()[vertex])):
                 if not Float.fuzzyCompare(result.getPoints()[vertex][dimension], data["answer"][vertex][dimension]):
                     thisCorrect = False
                     break #Break out of two loops.
             if not thisCorrect:
                 break
         if thisCorrect: #All vertices checked and it's still correct.
             isCorrect = True
             break
         result.setPoints(numpy.roll(result.getPoints(), 1, axis = 0)) #Perform the rotation for the next check.
     assert isCorrect
Пример #18
0
    def setX(self, x: str) -> None:
        parsed_x = self._parseInt(x)
        bounding_box = Selection.getBoundingBox()

        if not Float.fuzzyCompare(parsed_x, float(bounding_box.center.x), DIMENSION_TOLERANCE):
            selected_nodes = self._getSelectedObjectsWithoutSelectedAncestors()
            if len(selected_nodes) > 1:
                op = GroupedOperation()
                for selected_node in self._getSelectedObjectsWithoutSelectedAncestors():
                    world_position = selected_node.getWorldPosition()
                    new_position = world_position.set(x = parsed_x + (world_position.x - bounding_box.center.x))
                    node_op = TranslateOperation(selected_node, new_position, set_position = True)
                    op.addOperation(node_op)
                op.push()
            else:
                for selected_node in self._getSelectedObjectsWithoutSelectedAncestors():
                    world_position = selected_node.getWorldPosition()
                    new_position = world_position.set(x = parsed_x + (world_position.x - bounding_box.center.x))
                    TranslateOperation(selected_node, new_position, set_position = True).push()

        self._controller.toolOperationStopped.emit(self)
Пример #19
0
    def test_intersectsPolygon(self, data):
        p1 = Polygon(numpy.array([ #The base polygon to intersect with.
            [ 0,  0],
            [10,  0],
            [10, 10],
            [ 0, 10]
        ], numpy.float32))
        p2 = Polygon(numpy.array(data["polygon"])) #The parametrised polygon to intersect with.

        #Shift the order of vertices in both polygons around. The outcome should be independent of what the first vertex is.
        for n in range(0, len(p1.getPoints())):
            for m in range(0, len(data["polygon"])):
                result = p1.intersectsPolygon(p2)
                if not data["answer"]: #Result should be None.
                    assert result == None
                else:
                    assert result != None
                    for i in range(0, len(data["answer"])):
                        assert Float.fuzzyCompare(result[i], data["answer"][i])
                p2.setPoints(numpy.roll(p2.getPoints(), 1, axis = 0)) #Shift p2.
            p1.setPoints(numpy.roll(p1.getPoints(), 1, axis = 0)) #Shift p1.
Пример #20
0
    def setY(self, y: str) -> None:
        parsed_y = self._parseInt(y)
        bounding_box = Selection.getBoundingBox()

        if not Float.fuzzyCompare(parsed_y, float(bounding_box.center.z), DIMENSION_TOLERANCE):
            selected_nodes = self._getSelectedObjectsWithoutSelectedAncestors()
            if len(selected_nodes) > 1:
                op = GroupedOperation()
                for selected_node in selected_nodes:
                    # Note; The switching of z & y is intentional. We display z as up for the user,
                    # But store the data in openGL space.
                    world_position = selected_node.getWorldPosition()
                    new_position = world_position.set(z = parsed_y + (world_position.z - bounding_box.center.z))
                    node_op = TranslateOperation(selected_node, new_position, set_position = True)
                    op.addOperation(node_op)
                op.push()
            else:
                for selected_node in selected_nodes:
                    world_position = selected_node.getWorldPosition()
                    new_position = world_position.set(z = parsed_y + (world_position.z - bounding_box.center.z))
                    TranslateOperation(selected_node, new_position, set_position = True).push()

        self._controller.toolOperationStopped.emit(self)
Пример #21
0
 def equals(self, other, epsilon = 1e-6):
     return Float.fuzzyCompare(self.x, other.x, epsilon) and \
            Float.fuzzyCompare(self.y, other.y, epsilon) and \
            Float.fuzzyCompare(self.z, other.z, epsilon)
Пример #22
0
    def intersectionConvexHulls(self, other):
        me = self.getConvexHull()
        him = other.getConvexHull()

        if len(me._points) <= 2 or len(him._points) <= 2: #If either polygon has no surface area, then the intersection is empty.
            return Polygon()

        index_me = 0 #The current vertex index.
        index_him = 0
        advances_me = 0 #How often we've advanced.
        advances_him = 0
        who_is_inside = "unknown" #Which of the two polygons is currently on the inside.
        directions_me = numpy.subtract(numpy.roll(me._points, -1, axis = 0), me._points) #Pre-compute the difference between consecutive points to get a direction for each point.
        directions_him = numpy.subtract(numpy.roll(him._points, -1, axis = 0), him._points)
        result = []

        #Iterate through both polygons until we've made a loop through both polygons.
        while advances_me <= len(me._points) or advances_him <= len(him._points):
            vertex_me = me._points[index_me]
            vertex_him = him._points[index_him]
            if advances_me > len(me._points) * 2 or advances_him > len(him._points) * 2: #Also, if we've looped twice through either polygon, the boundaries of the polygons don't intersect.
                if len(result) > 2:
                    return result
                if me.isInside(vertex_him): #Other polygon is inside this one.
                    return him
                if him.isInside(vertex_me): #This polygon is inside the other.
                    return me
                #Polygons are disjunct.
                return Polygon()

            me_start = Vector2(data = vertex_me)
            me_end = Vector2(data = vertex_me + directions_me[index_me])
            him_start = Vector2(data = vertex_him)
            him_end = Vector2(data = vertex_him + directions_him[index_him])

            me_in_him_halfplane = (me_end - him_start).cross(him_end - him_start) #Cross gives positive if him_end is to the left of me_end (as seen from him_start).
            him_in_me_halfplane = (him_end - me_start).cross(me_end - me_start) #Arr, I's got him in me halfplane, cap'n.
            intersection = LineSegment(me_start, me_end).intersection(LineSegment(him_start, him_end))

            if intersection:
                result.append(intersection.getData()) #The intersection is always in the hull.
                if me_in_him_halfplane > 0: #At the intersection, who was inside changes.
                    who_is_inside = "me"
                elif him_in_me_halfplane > 0:
                    who_is_inside = "him"
                else:
                    pass #Otherwise, whoever is inside remains the same (or unknown).
                advances_me += 1
                index_me = (index_me + 1) % len(me._points)
                advances_him += 1
                index_him = (index_him + 1) % len(him._points)
                continue

            cross = (Vector2(data = directions_me[index_me]).cross(Vector2(data = directions_him[index_him])))
            
            #Edge case: Two exactly opposite edges facing away from each other.
            if Float.fuzzyCompare(cross, 0) and me_in_him_halfplane <= 0 and him_in_me_halfplane <= 0:
                # The polygons must be disjunct then.
                return Polygon()

            if Float.fuzzyCompare(cross, 0) and directions_me[index_me].dot(directions_him[index_him]) < 0 and me_in_him_halfplane > 0:
                #Just advance the inside.
                if who_is_inside == "him":
                    advances_him += 1
                    index_him = (index_him + 1) % len(him._points)
                else: #him OR unknown! If it's unknown, it doesn't matter which one is advanced, since it only happens when the starting edge was already colinear.
                    advances_me += 1
                    index_me = (index_me + 1) % len(me._points)
                continue

            #Edge case: Two colinear edges.
            if Float.fuzzyCompare(cross, 0): #Two edges overlap.
                #Just advance the outside.
                if who_is_inside == "me":
                    advances_him += 1
                    index_him = (index_him + 1) % len(him._points)
                else: #him OR unknown! If it's unknown, it doesn't matter which one is advanced, since it only happens when the starting edge was already colinear.
                    advances_me += 1
                    index_me = (index_me + 1) % len(me._points)
                continue

            #Generic case: Advance whichever polygon is on the outside.
            if cross >= 0: #This polygon is going faster towards the inside.
                if him_in_me_halfplane > 0:
                    advances_me += 1
                    index_me = (index_me + 1) % len(me._points)
                    if who_is_inside == "him":
                        result.append(vertex_him)
                else:
                    advances_him += 1
                    index_him = (index_him + 1) % len(him._points)
                    if who_is_inside == "me":
                        result.append(vertex_me)
            else: #The other polygon is going faster towards the inside.
                if me_in_him_halfplane > 0:
                    advances_him += 1
                    index_him = (index_him + 1) % len(him._points)
                    if who_is_inside == "me":
                        result.append(vertex_me)
                else:
                    advances_me += 1
                    index_me = (index_me + 1) % len(me._points)
                    if who_is_inside == "him":
                        result.append(vertex_him)
        return Polygon(points = result)
Пример #23
0
 def __eq__(self, other):
     return Float.fuzzyCompare(
         self.x, other.x, 1e-6) and Float.fuzzyCompare(
             self.y, other.y, 1e-6) and Float.fuzzyCompare(
                 self.z, other.z, 1e-6) and Float.fuzzyCompare(
                     self.w, other.w, 1e-6)
Пример #24
0
    def intersectionConvexHulls(self, other):
        me = self.getConvexHull()
        him = other.getConvexHull()

        if len(me._points) <= 2 or len(him._points) <= 2: #If either polygon has no surface area, then the intersection is empty.
            return Polygon()

        index_me = 0 #The current vertex index.
        index_him = 0
        advances_me = 0 #How often we've advanced.
        advances_him = 0
        who_is_inside = "unknown" #Which of the two polygons is currently on the inside.
        directions_me = numpy.subtract(numpy.roll(me._points, -1, axis = 0), me._points) #Pre-compute the difference between consecutive points to get a direction for each point.
        directions_him = numpy.subtract(numpy.roll(him._points, -1, axis = 0), him._points)
        result = []

        #Iterate through both polygons to find intersections and inside vertices until we've made a loop through both polygons.
        while advances_me <= len(me._points) or advances_him <= len(him._points):
            vertex_me = me._points[index_me]
            vertex_him = him._points[index_him]
            if advances_me > len(me._points) * 2 or advances_him > len(him._points) * 2: #Also, if we've looped twice through either polygon, the boundaries of the polygons don't intersect.
                if len(result) > 2:
                    return Polygon(points = result)
                if me.isInside(vertex_him): #Other polygon is inside this one.
                    return him
                if him.isInside(vertex_me): #This polygon is inside the other.
                    return me
                #Polygons are disjunct.
                return Polygon()

            me_start = Vector2(data = vertex_me)
            me_end = Vector2(data = vertex_me + directions_me[index_me])
            him_start = Vector2(data = vertex_him)
            him_end = Vector2(data = vertex_him + directions_him[index_him])

            me_in_him_halfplane = (me_end - him_start).cross(him_end - him_start) #Cross gives positive if him_end is to the left of me_end (as seen from him_start).
            him_in_me_halfplane = (him_end - me_start).cross(me_end - me_start) #Arr, I's got him in me halfplane, cap'n.
            intersection = LineSegment(me_start, me_end).intersection(LineSegment(him_start, him_end))

            if intersection:
                result.append(intersection.getData()) #The intersection is always in the hull.
                if me_in_him_halfplane > 0: #At the intersection, who was inside changes.
                    who_is_inside = "me"
                elif him_in_me_halfplane > 0:
                    who_is_inside = "him"
                else:
                    pass #Otherwise, whoever is inside remains the same (or unknown).
                advances_me += 1
                index_me = advances_me % len(me._points)
                advances_him += 1
                index_him = advances_him % len(him._points)
                continue

            cross = (Vector2(data = directions_me[index_me]).cross(Vector2(data = directions_him[index_him])))

            #Edge case: Two exactly opposite edges facing away from each other.
            if Float.fuzzyCompare(cross, 0) and me_in_him_halfplane <= 0 and him_in_me_halfplane <= 0:
                # The polygons must be disjunct then.
                return Polygon()

            #Edge case: Two colinear edges.
            if Float.fuzzyCompare(cross, 0) and me_in_him_halfplane <= 0:
                advances_me += 1
                index_me = advances_me % len(me._points)
                continue
            if Float.fuzzyCompare(cross, 0) and him_in_me_halfplane <= 0:
                advances_him += 1
                index_him = advances_him % len(him._points)
                continue

            #Edge case: Two edges overlap.
            if Float.fuzzyCompare(cross, 0):
                #Just advance the outside.
                if who_is_inside == "me":
                    advances_him += 1
                    index_him = advances_him % len(him._points)
                else: #him or unknown. If it's unknown, it doesn't matter which one is advanced, as long as it's the same polygon being advanced every time (me in this case).
                    advances_me += 1
                    index_me = advances_me % len(me._points)
                continue

            #Generic case: Advance whichever polygon is on the outside.
            if cross >= 0: #This polygon is going faster towards the inside.
                if him_in_me_halfplane > 0:
                    advances_me += 1
                    index_me = advances_me % len(me._points)
                    if who_is_inside == "him":
                        result.append(vertex_him)
                else:
                    advances_him += 1
                    index_him = advances_him % len(him._points)
                    if who_is_inside == "me":
                        result.append(vertex_me)
            else: #The other polygon is going faster towards the inside.
                if me_in_him_halfplane > 0:
                    advances_him += 1
                    index_him = advances_him % len(him._points)
                    if who_is_inside == "me":
                        result.append(vertex_me)
                else:
                    advances_me += 1
                    index_me = advances_me % len(me._points)
                    if who_is_inside == "him":
                        result.append(vertex_him)
        if (result[0] == result[-1]).all(): #If the last two edges are parallel, the first vertex will have been added again. So if it is the same as the last element, remove it.
            result = result[:-1] #This also handles the case where the intersection is only one point.
        return Polygon(points = result)
Пример #25
0
 def isValid(self):
     return not(Float.fuzzyCompare(self._min.x, self._max.x) or
                Float.fuzzyCompare(self._min.y, self._max.y) or
                Float.fuzzyCompare(self._min.z, self._max.z))
Пример #26
0
 def intersectsWithLine(self, a, b):
     shifted_b = b - a
     #It intersects if either endpoint is on the line, or if one endpoint is on the right but the other is not.
     return Float.fuzzyCompare(shifted_b.cross(self._endpoint_a), 0) or Float.fuzzyCompare(shifted_b.cross(self._endpoint_b), 0) or (self._pointIsRight(self._endpoint_a, a, b) != self._pointIsRight(self._endpoint_b, a, b))
Пример #27
0
    def test_translateWorld(self):
        node1 = SceneNode()

        node2 = SceneNode(node1)

        self.assertEqual(node2.getWorldPosition(), Vector(0, 0, 0))

        node1.translate(Vector(0, 0, 10))

        self.assertEqual(node1.getWorldPosition(), Vector(0, 0, 10))
        self.assertEqual(node2.getWorldPosition(), Vector(0, 0, 10))

        node2.translate(Vector(0, 0, 10))

        self.assertEqual(node1.getWorldPosition(), Vector(0, 0, 10))
        self.assertEqual(node2.getWorldPosition(), Vector(0, 0, 20))

        node1.rotate(Quaternion.fromAngleAxis(math.pi / 2, Vector.Unit_Y))

        self.assertEqual(node1.getWorldPosition(), Vector(0, 0, 10))
        self.assertEqual(node2.getWorldPosition(), Vector(10, 0, 10))

        node2.translate(Vector(0, 0, 10))

        # Local translation on Z with a parent rotated 90 degrees results in movement on X axis
        pos = node2.getWorldPosition()
        #Using fuzzyCompare due to accumulation of floating point error
        self.assertTrue(Float.fuzzyCompare(pos.x, 20, 1e-5), "{0} does not equal {1}".format(pos, Vector(20, 0, 10)))
        self.assertTrue(Float.fuzzyCompare(pos.y, 0, 1e-5), "{0} does not equal {1}".format(pos, Vector(20, 0, 10)))
        self.assertTrue(Float.fuzzyCompare(pos.z, 10, 1e-5), "{0} does not equal {1}".format(pos, Vector(20, 0, 10)))

        node2.translate(Vector(0, 0, 10), SceneNode.TransformSpace.World)

        # World translation on Z with a parent rotated 90 degrees results in movement on Z axis
        pos = node2.getWorldPosition()
        self.assertTrue(Float.fuzzyCompare(pos.x, 20, 1e-5), "{0} does not equal {1}".format(pos, Vector(20, 0, 20)))
        self.assertTrue(Float.fuzzyCompare(pos.y, 0, 1e-5), "{0} does not equal {1}".format(pos, Vector(20, 0, 20)))
        self.assertTrue(Float.fuzzyCompare(pos.z, 20, 1e-5), "{0} does not equal {1}".format(pos, Vector(20, 0, 20)))

        node1.translate(Vector(0, 0, 10))

        self.assertEqual(node1.getWorldPosition(), Vector(10, 0, 10))

        pos = node2.getWorldPosition()
        self.assertTrue(Float.fuzzyCompare(pos.x, 30, 1e-5), "{0} does not equal {1}".format(pos, Vector(30, 0, 20)))
        self.assertTrue(Float.fuzzyCompare(pos.y, 0, 1e-5), "{0} does not equal {1}".format(pos, Vector(30, 0, 20)))
        self.assertTrue(Float.fuzzyCompare(pos.z, 20, 1e-5), "{0} does not equal {1}".format(pos, Vector(30, 0, 20)))

        node1.scale(Vector(2, 2, 2))

        pos = node2.getWorldPosition()
        self.assertTrue(Float.fuzzyCompare(pos.x, 50, 1e-4), "{0} does not equal {1}".format(pos, Vector(50, 0, 30)))
        self.assertTrue(Float.fuzzyCompare(pos.y, 0, 1e-4), "{0} does not equal {1}".format(pos, Vector(50, 0, 30)))
        self.assertTrue(Float.fuzzyCompare(pos.z, 30, 1e-4), "{0} does not equal {1}".format(pos, Vector(50, 0, 30)))

        node2.translate(Vector(0, 0, 10))

        pos = node2.getWorldPosition()
        self.assertTrue(Float.fuzzyCompare(pos.x, 70, 1e-4), "{0} does not equal {1}".format(pos, Vector(70, 0, 30)))
        self.assertTrue(Float.fuzzyCompare(pos.y, 0, 1e-4), "{0} does not equal {1}".format(pos, Vector(70, 0, 30)))
        self.assertTrue(Float.fuzzyCompare(pos.z, 30, 1e-4), "{0} does not equal {1}".format(pos, Vector(70, 0, 30)))

        # World space set position
        node1 = SceneNode()
        node2 = SceneNode(node1)
        node1.setPosition(Vector(15,15,15))
        node2.setPosition(Vector(10,10,10))
        self.assertEqual(node2.getWorldPosition(), Vector(25, 25, 25))
        node2.setPosition(Vector(15,15,15), SceneNode.TransformSpace.World)
        self.assertEqual(node2.getWorldPosition(), Vector(15, 15, 15))
        self.assertEqual(node2.getPosition(), Vector(0,0,0))

        node1.setPosition(Vector(15,15,15))
        node2.setPosition(Vector(0,0,0))
        node2.rotate(Quaternion.fromAngleAxis(-math.pi / 2, Vector.Unit_Y))
        node2.translate(Vector(10,0,0))
        self.assertEqual(node2.getWorldPosition(), Vector(15,15,25))

        node2.setPosition(Vector(15,15,25), SceneNode.TransformSpace.World)
        self.assertEqual(node2.getWorldPosition(), Vector(15,15,25))
        self.assertEqual(node2.getPosition(), Vector(0,0,10))
Пример #28
0
 def __eq__(self, other):
     return Float.fuzzyCompare(self.x, other.x, 1e-6) and Float.fuzzyCompare(self.y, other.y, 1e-6) and Float.fuzzyCompare(self.z, other.z, 1e-6)
Пример #29
0
    def test_toMatrix(self):
        q1 = Quaternion()
        q1.setByAngleAxis(math.pi / 2, Vector.Unit_Z)

        m1 = q1.toMatrix()

        m2 = Matrix()
        m2.setByRotationAxis(math.pi / 2, Vector.Unit_Z)

        self.assertTrue(Float.fuzzyCompare(m1.at(0, 0), m2.at(0, 0), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(0, 1), m2.at(0, 1), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(0, 2), m2.at(0, 2), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(0, 3), m2.at(0, 3), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(1, 0), m2.at(1, 0), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(1, 1), m2.at(1, 1), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(1, 2), m2.at(1, 2), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(1, 3), m2.at(1, 3), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(2, 0), m2.at(2, 0), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(2, 1), m2.at(2, 1), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(2, 2), m2.at(2, 2), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(2, 3), m2.at(2, 3), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(3, 0), m2.at(3, 0), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(3, 1), m2.at(3, 1), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(3, 2), m2.at(3, 2), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(3, 3), m2.at(3, 3), 1e-6))
Пример #30
0
    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

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

            # Move the node upwards if the bottom is below the build platform.
            move_vector = Vector()
            if not Float.fuzzyCompare(bbox.bottom, 0.0):
                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 Selection.isSelected(node):
                pass
            else:
                # 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:
                        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.
                    overlap = node.callDecoration("getConvexHull").intersectsPolygon(other_node.callDecoration("getConvexHull"))
                    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:
                # 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()
Пример #31
0
 def equals(self, other, epsilon=1e-6):
     return Float.fuzzyCompare(self.x, other.x, epsilon) and \
            Float.fuzzyCompare(self.y, other.y, epsilon) and \
            Float.fuzzyCompare(self.z, other.z, epsilon)
Пример #32
0
 def isValid(self) -> bool:
     return not(Float.fuzzyCompare(self._min.x, self._max.x) or
                Float.fuzzyCompare(self._min.y, self._max.y) or
                Float.fuzzyCompare(self._min.z, self._max.z))
Пример #33
0
    def test_toMatrix(self):
        q1 = Quaternion()
        q1.setByAngleAxis(math.pi / 2, Vector.Unit_Z)

        m1 = q1.toMatrix()

        m2 = Matrix()
        m2.setByRotationAxis(math.pi / 2, Vector.Unit_Z)

        self.assertTrue(Float.fuzzyCompare(m1.at(0, 0), m2.at(0, 0), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(0, 1), m2.at(0, 1), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(0, 2), m2.at(0, 2), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(0, 3), m2.at(0, 3), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(1, 0), m2.at(1, 0), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(1, 1), m2.at(1, 1), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(1, 2), m2.at(1, 2), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(1, 3), m2.at(1, 3), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(2, 0), m2.at(2, 0), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(2, 1), m2.at(2, 1), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(2, 2), m2.at(2, 2), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(2, 3), m2.at(2, 3), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(3, 0), m2.at(3, 0), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(3, 1), m2.at(3, 1), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(3, 2), m2.at(3, 2), 1e-6))
        self.assertTrue(Float.fuzzyCompare(m1.at(3, 3), m2.at(3, 3), 1e-6))