Example #1
0
    def compute_centroids(self, vectors):
        count = len(vectors)
        assert count >= 3

        c = Box2D.b2Vec2(0, 0)
        area = 0

        ref_point = Box2D.b2Vec2(0, 0)
        inv3 = 1 / 3

        for i in range(count):
            # Triangle vertices
            p1 = ref_point
            p2 = vectors[i]
            p3 = vectors[i + 1] if i + 1 < count else vectors[0]

            e1 = p2 - p1
            e2 = p3 - p1

            d = Box2D.b2Cross(e1, e2)

            triangle_area = 0.5 * d
            area += triangle_area

            # Area weighted centroid
            c += triangle_area * inv3 * (p1 + p2 + p3)

        if area > Box2D.b2_epsilon:
            c *= 1 / area
        else:
            area = 0

        return c, area
Example #2
0
    def calculate_forces(self, fixture_pairs):
        for pair in fixture_pairs:
            density = pair[0].density

            has_intersection, intersection_points = self.find_intersection(
                pair[0], pair[1])

            if has_intersection:
                centroid, area = self.compute_centroids(intersection_points)

                # apply buoyancy force
                displaced_mass = pair[0].density * area
                buoyancy_force = displaced_mass * -self.gravity
                pair[1].body.ApplyForce(force=buoyancy_force,
                                        point=centroid,
                                        wake=True)

                # apply complex drag
                for i in range(len(intersection_points)):
                    v0 = intersection_points[i]
                    v1 = intersection_points[(i + 1) %
                                             len(intersection_points)]
                    mid_point = 0.5 * (v0 + v1)

                    ##### DRAG
                    # find relative velocity between object and fluid at edge midpoint
                    vel_dir = pair[1].body.GetLinearVelocityFromWorldPoint(mid_point) - \
                              pair[0].body.GetLinearVelocityFromWorldPoint(mid_point)
                    vel = vel_dir.Normalize()

                    edge = v1 - v0
                    edge_length = edge.Normalize()
                    normal = Box2D.b2Cross(-1, edge)
                    drag_dot = Box2D.b2Dot(normal, vel_dir)
                    if drag_dot >= 0:  # normal points backwards - this is not a leading edge
                        # apply drag
                        drag_mag = drag_dot * self.drag_mod * edge_length * density * vel * vel
                        drag_mag = min(drag_mag, self.max_drag)
                        drag_force = drag_mag * -vel_dir
                        pair[1].body.ApplyForce(force=drag_force,
                                                point=mid_point,
                                                wake=True)

                        # apply lift
                        lift_dot = Box2D.b2Dot(edge, vel_dir)
                        lift_mag = drag_dot * lift_dot * self.lift_mod * edge_length * density * vel * vel
                        lift_mag = min(lift_mag, self.max_lift)
                        lift_dir = Box2D.b2Cross(1, vel_dir)
                        lift_force = lift_mag * lift_dir
                        pair[1].body.ApplyForce(force=lift_force,
                                                point=mid_point,
                                                wake=True)
                    ##### PUSH
                    # Apply a linear force to an object linked to a rotation joint applying torque.
                    # Torque and angular inertia are used to calculate the magnitude of the linear force

                    body_to_check = pair[1].body
                    # Simplification /!\
                    # joint = pair[1].body.joints[0].joint
                    # joints_to_check = [joint_edge.joint for joint_edge in body_to_check.joints]
                    joints_to_check = [
                        joint_edge.joint for joint_edge in body_to_check.joints
                        if joint_edge.joint.bodyB == body_to_check
                    ]

                    for joint in joints_to_check:
                        if joint.lowerLimit < joint.angle < joint.upperLimit:
                            torque = joint.GetMotorTorque(60)

                            # Calculate angular inertia of the object
                            moment_of_inertia = body_to_check.inertia
                            angular_velocity = body_to_check.angularVelocity
                            angular_inertia = moment_of_inertia * angular_velocity

                            # Calculate the force applied to the object
                            world_center = body_to_check.worldCenter
                            anchor = joint.anchorB
                            lever_vector = world_center - anchor  # vector from pivot to point of application of the force
                            force_applied_at_center = Box2D.b2Cross(
                                lever_vector, -torque)

                            push_dot = Box2D.b2Dot(normal,
                                                   force_applied_at_center)
                            if push_dot > 0:
                                vel = torque + angular_inertia
                                push_mag = push_dot * self.push_mod * edge_length * density * vel * vel  # Wrong approximation /!\
                                # push_mag = min(push_mag, self.max_push)
                                push_force = np.clip(
                                    push_mag * -force_applied_at_center,
                                    -self.max_push, self.max_push)
                                body_to_check.ApplyForce(
                                    force=push_force,
                                    point=joint.
                                    anchorB,  #body_to_check.worldCenter,
                                    wake=True)